When connecting USB to my Arduino, I need to wait +/- 10 seconds before being able to send commands

I'm using a native Arduino MEGA 2560 and a (Chinese) clone, and experience the same issue.

I have a simple communication between a Console based application in C# (using Visual Studio 2022 on a Windows 10 machine) and the Arduino. My C# app and my Arduino can communicate through the Serial Port with no issues..

But in my C# application I can detect if an Arduino is disconnected from or connect to the USB port (using WMI). When I detect a (re)connection, my C# app opens the SerialPort and does some communication with the Arduino based on sending some string commands on which I receive some string answers (all terminated by "\n").

But in many cases that results in a "Timeout Exception", which means that I'm not receiving anything back from the Arduino. If I connect an external "Serial Port Monitor", I see that the Arduino in such case returns some random character (sometimes 2), and then it stops. I can retry my command over and over again, but nothing comes back.

But in case my Arduino is "stuck", and I wait more than 10 seconds before I resend a command after a timeout, then it works again. It is as after disconnecting/reconnecting my USB cable, the Arduino goes in some kind of state that doesn't allow any communication. If I repeat my commands every few seconds, it stays in that state. Only if I maintain complete communication silence for >10seconds, it "unlocks", and I can start communicating again.

So basically, the below shows a bit in pseudocode what happens:

1 - I power up my Arduino with external power
2 - I connect the USB cable
3 - C# App detects the connection, and can identify the Port where Arduino is connected (example: "COM6")
4 - C# App opens the SerialPort (8N1 - 500000baud - read timeout 2000msec, write timeout 1000msec)
5 - C# App sleeps 12 seconds (needs to be at least 10 seconds, or it "might" not work)
6 - C# App sends "\n" and clears input buffer (this is to bring Arduino in start position, and gets rid of all data that could still be in the input buffer of the C# app)
7 - C# App sends "IDENT\n"
8 - Arduino replies with "TEST Module\n" and "ARDUINO\n"
9 - C# App sends "REGISTER\n"
10 - Arduino answers with 3 strings, each one terminated by "\n", and one final "\n" to terminate the registration sequence

If I now disconnect the USB cable, the C# app detects that, and closes the SerialPort. When I then reconnect the USB cable, it all starts over at step 2.

I also did some tests with the IDE (I'm using version 2.2.1). I open my Serial Monitor and can communicate with my Arduino. Then I disconnect my Arduino from the USB, and reconnect it again a few seconds later. In some cases, I get immediate replies on my IDENT command. But in some cases, it doesn't. This means, if I type "IDENT" and press (my setup is "New Line"), I don't get a response. If I repeat my command over and over again, I don't get anything back. But if I stop sending commands for 10 seconds, and then I type "IDENT" again, it suddenly answers. So the IDE kind of shows the same behavior as my C# app.

QUESTION: Can somebody explain this behavior? Is this documented somewhere? And most important, is there a way to get rid of that delay? Of is this "by design", and is the safest approach indeed to wait 10 seconds after a first failed communication attempt (which just works fine for me now).

The relevant code in my Arduino is shown below. The parts relevant for this discussion is the 'SerialEvent()' (I added a few LED toggles trying to trace some stuff) and the 'loop()' where you can see the processing of the "IDENT" and "REGISTER" commands.

#include "src/ButtonClass/ButtonClass.h"

// Command related items
#define CMD_SIZE 100
char sBuffer[CMD_SIZE];
char sCommand[CMD_SIZE];
char* sParameter;
int iRxPtr = 0;
bool bCmdReady = false;
bool bRegistered = false;

// Global variables for Serial communication
const long baudrate = 500000;

// IDENT
const String sIdent = "TEST Module\n";
const String sProcessor = "ARDUINO\n";

// variables (variables start at 001
const char *Variables[] = {
  "FLOAT64_R_A:AUTOPILOT ALTITUDE LOCK VAR:3,feet",     // 001
  "VOID_K:A32NX.FCU_HDG_INC",                           // 002
  "VOID_K:A32NX.FCU_HDG_DEC",                           // 003
  };
size_t nVariables = sizeof(Variables)/sizeof(Variables[0]);

// Easy way to toggle an LED
void ToggleLed(int pin) { digitalWrite(pin, !digitalRead(pin)); }

// Acknowledge
#define ACK Serial.print("A\n")

// Buttons
#define BTN_HDG_INC 40
#define BTN_HDG_DEC 41
ButtonClass bcHDG_INC = ButtonClass(BTN_HDG_INC, 50);
ButtonClass bcHDG_DEC = ButtonClass(BTN_HDG_DEC, 50);

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  Serial.begin(baudrate, SERIAL_8N1);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (bCmdReady) {

    // Process IDENT command
    if (strcmp(sCommand, "IDENT") == 0) {
      Serial.print(sIdent);
      Serial.print(sProcessor);
    }

    // Process REGISTER command
    else if (strcmp(sCommand, "REGISTER") == 0) {
      for (int i = 0; i < nVariables; i++)
      {
        Serial.print(Variables[i]);
        Serial.print("\n");
      }
      Serial.print("\n");
      bRegistered = true;
    }

    else if (bRegistered) {
      // Reset bRegistered flag - do not send ACK
      if (strcmp(sCommand, "RESET") == 0)
      {
        bRegistered = false;
        ToggleLed(LED_BUILTIN);
      }

      else if ((strlen(sCommand) > 4) && (sCommand[3] == '='))
      {
        // Assumed that "NNN=..." is received
        
        ACK;

        sCommand[3] = '\0';
        sParameter = &sCommand[4];

        int iID = atoi(sCommand);
        if (iID != 0)
        {
          switch (iID) {
            case 1: // FLOAT64_R_A:AUTOPILOT ALTITUDE LOCK VAR:3,feet
            {
              ToggleLed(LED_BUILTIN);
              break;
            }
            default:
              break;
          }
        }
      }
    }
    bCmdReady = false;
  }

  if (bRegistered) {
    // Process INC
    if (bcHDG_INC.ButtonState() == OFF_ON) {
      Serial.print("002=1\n"); // VOID_K:A32NX.FCU_HDG_INC
    }
    
    // Process DEC
    if (bcHDG_DEC.ButtonState() == OFF_ON) {
      Serial.print("003=1\n"); // VOID_K:A32NX.FCU_HDG_DEC
    }
  }
}

void serialEvent()
{
  while (Serial.available())
  {
    char cCmd = Serial.read();
    ToggleLed(LED_BUILTIN);
    if (cCmd == '\n')
    {
      sBuffer[iRxPtr] = 0;        // terminate string
      strcpy(sCommand, sBuffer);  // copy sBuffer in sCommand
      bCmdReady = true;           // indicate that command is available
      ToggleLed(LED_BUILTIN);
      iRxPtr = 0;
    }
    else if (cCmd != '\r')
      sBuffer[iRxPtr++] = cCmd;
  }
}

HI @hansbilliet ,

did you check if the same behaviour applies at lower baudrates, like e.g. 115200?

Edit: Just found that CH340 does not support 500.000 Baud but 460.800 ... See

https://cdn.sparkfun.com/assets/5/0/a/8/5/CH340DS1.PDF

Not sure but you could give it a try ...

Good luck!

When the Arduino first starts up the boot loader sends a command sequence to see if there is new code to download. If it doesn't get an expected response after a certain period it branches to the loaded code.

If it gets something other than than the download handshake response that response is thrown away. The Arduino is reset and the boot loader called every time the USB is reconnected.

Try waiting a few seconds after the PC connects before sending a command. In my Python code I wait 2 seconds and then flush anything received (the boot loader request) from the Arduino.

Hello @ec2021,

I just did a test with 19200 baud using the IDE (that already rules out my C# app), and it behaves exactly the same.

  1. I change my sketch to use 19200 baud, and also changed the setup of Serial Monitor to 19200 baud
  2. I first do a test, and all works fine - I receive answer to my IDENT command
  3. I disconnect my Arduino from my USB
  4. I reconnect, and when Serial Monitor comes alive, I immediately send the IDENT command
    --> no answer from my Arduino (I was lucky as it occurred immediately)
  5. I repeatedly send the command for about 30 seconds
    --> Arduino stays in this "locked state" as long as I send commands
  6. I wait about 10 seconds
  7. I send my IDENT command
    --> Now the Arduino "comes alive" and sends its answer

Can it not be that the Arduino is in some kind of status that expects loading new firmware? In this status, it might be looking for some special commands or instructions and of course ignores my commands. As long I keep sending commands, it stays in that status. Once I stop sending, it returns back to normal operation after 10 seconds of "silence". The only question is then, does it always enters that state after disconnect/reconnect USB? I wonder if this is documented somewhere.

Hello @oldcurmudgeon,

It appears that 2 seconds is not enough for some reason. I have the feeling that 10 seconds is the hot spot. I wait 12 seconds now. This is not a problem in my final software, because it only happens when dealing with Arduino (I normally work with PIC-microcontrollers that I manage myself). And it only happens when physically manipulating the USB connecting while running my software, so it's rare. And even if it would happen with 10 simultaneously connected Arduino's, my software works asynchronously, so the delays don't add up.

But still, would be nice to find some documentation about this behavior.

Hans

Hmm, there were web pages that described the boot loader and the process. They seem to have been deleted - all I get now is page not found. I don't know if they have been moved or the information just deleted. All I find now is how to burn a bootloader.

The other possibility is to write your code directly to the chip, bypassing the boot sequence. It is a bit more involved because you need a hardware programmer and it is a bit more complex procedure. The up side is it starts immediately with your code.

I have never experienced this behavior yet and would doubt that the controller waits for any firmware just because of serial input received. Usually the DTR signal dropping LOW for a short time is used to reset the controller when a USB connection is established.

You could implement a simple blink without delay function in loop to see if the controller stops or if loop is running ... If you set another led on start of setup and shut it off at end of setup you could also verify that setup is performed...

Thanks @oldcurmudgeon. But to avoid all confusion, I do not want to load my code in a different way. I just want to understand why my 2 Arduino's behave as described above.

Hello @ec2021. Just for curiosity, I might just do that and add some LED-tracing in my code to see what is really happening.

What is strange is that nobody knows what is exactly going on, although I have 2 completely different Arduino's behaving exactly the same with the Arduino IDE. Although I do have a solution for my problem now (wait 12sec and then retry), I would like to know the why.

I fully understand that. I've got just one Uno, one Mega, one Leonardo and a couple of Nanos as well as ESP32 but did not see anything like you described.

So I'm also curious... :wink:

I managed to run your sketch on Wokwi:

With a self-written ButtonClass.h it does not show any delays or problems ... Hope I got the idea of your ButtonClass ... :wink:

#pragma once

enum buttonStates {IDLE, OFF_ON, ON_OFF};

class ButtonClass {
  private:
     byte buttonPin;
     byte prevState = HIGH;
     byte state = HIGH;
     unsigned long lastChange = 0;
     unsigned long debounceTime = 20;
  public:
   ButtonClass(byte Pin, unsigned long debounceInterval);
   buttonStates ButtonState();
};

ButtonClass::ButtonClass(byte Pin, unsigned long debounceInterval){
  buttonPin = Pin;
  pinMode(buttonPin, INPUT_PULLUP);
  debounceTime = debounceInterval;
}

buttonStates ButtonClass::ButtonState(){
  byte actState = digitalRead(buttonPin);
  if (actState != prevState){
    lastChange = millis();
    prevState = actState;
  } 
  if (state != actState && millis()-lastChange > debounceTime){
    state = actState;
    if (state == HIGH) {
       return ON_OFF;
    } else {
       return OFF_ON;
    }
  }
  return IDLE;
}

Would you mind to post your solution of ButtonClass, just to get the full (software) picture?

Do you mean you have the IDE's serial monitor open and your C# code trying to connect to the Arduino?

Set the DtrEnable and RtsEnable properties of your SerialPort object to false in the C# code before opening the port.

This is from some existing code that I have where the properties are taken from checkboxes (cbXX). sp is the SerialPort object.

            sp.DtrEnable = cbDTR.Checked;
            sp.RtsEnable = cbRTS.Checked;

Hello @J-M-L . No, obviously not because that is not possible, I know. I started this post by explaining my C# app, but I then also started checking if the same issue happens also with the IDE, and it does. So my C# app is kind of irrelevant now.

No, it isn't irrelevant. DTR / RTS control the reset line of the main processor; disabling them (see my previous reply) will prevent the reset from happening.

I have checked your sketch (with my own ButtonClass as mentioned above) with a MEGA 2560 from Funduino and Arduino IDE 2.2.1 (Windows 11) and it worked without problems here ...

How about your ButtonClass.h ?

@ec2021 @sterretje @J-M-L @oldcurmudgeon

I did a few more tests. Here is an attempt to describe all the results.

First I made a simple sketch to analyze the behavior of the LED_BUILTIN.

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
}

void loop() {
  digitalWrite(LED_BUILTIN, LOW);
}

If I disconnect my USB, and I power the Arduino with an external power supply, I see the LED blinking twice (2 x ON/OFF). I would expect it only to blink once. So there must be one "blink" that is not caused by my code.

To proof that I'm right, I simplified my code even more.

void setup() {
}

void loop() {
}

If I now disconnect my USB, and I power my Arduino, I see the LED blinking ON/OFF and then it goes on a second time and then goes out slowly (few seconds) like it is discharging from some capacitor.

My assumption is that the internal Arduino boot code is driving the BUILTIN_LED ON/OFF, and then it probably remains in an undefined state which makes the LED light up again and then discharge slowly. If my additional code is added, the LED is going to another ON/OFF cycle, hence it blinks twice.

If once the Arduino is started, and I connect the USB port, then it depends whether the Serial Monitor is switched on or not. If Serial Monitor is not running, the LED doesn't react. If Serial Monitor is running, then the LED acts as if I connected it to the power as in my previous tests. This means that the LED is blinking ON/OFF, and then goes ON and slowly goes OFF.

My assumption is that when the Serial Monitor is running, it kind of forces a reset to the Arduino. Probably because the DTR/RTS pins (see comments from @sterretje ).

So far so good. Then I added some extra code to allow me to communicate with the Arduino. I kept it very basic this time. I only react to an empty string, which means that I press "ENTER" in the Serial Monitor. This allows me to interact fast and as precisely timed as possible.

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.begin(baudrate, SERIAL_8N1);
}

void loop() {
  digitalWrite(LED_BUILTIN, LOW);

  // put your main code here, to run repeatedly:
  if (bCmdReady) {

    if (strcmp(sCommand, "") == 0) {
      Serial.print("ENTER\n");
    }

    bCmdReady = false;
  }
}

void serialEvent()
{
  while (Serial.available())
  {
    char cCmd = Serial.read();
    if (cCmd == '\n')
    {
      sBuffer[iRxPtr] = 0;        // terminate string
      strcpy(sCommand, sBuffer);  // copy sBuffer in sCommand
      bCmdReady = true;           // indicate that command is available
      iRxPtr = 0;
    }
    else if (cCmd != '\r')
      sBuffer[iRxPtr++] = cCmd;
  }
}

I disconnect USB and Power. Then I connect the power. I see the BUILT_IN LED going "ON", "OFF", "ON", "OFF", which is totally expected based on the first experiments.

When I disconnect and then reconnect the USB port while my Serial Monitor is not running, I now see the LED going ON and OFF once. In my experiment above, the LED didn't react and now it does. This is most probably because I added the 'Serial.Open', which takes a short time to initialize the Serial Port. That could explain that I now see the LED blinking once.

When I run my Serial Monitor, and do the same test, then I see the LED blinking twice. That makes me assume that (probably due to the DTR/RTS - cfr. comment of @sterretje ) the Arduino this time starts it's power/on cycle, and then goes through the setup/loop. When I press "ENTER", now I get an answer "ENTER\n".

I discovered that when I reconnect the USB port, and I wait until my device is rebooted (I simply wait a short while), en then I press "ENTER" in the Serial Monitor, I get my answer "ENTER\n". So all works fine. But if I disconnect and then reconnect, and IMMEDIATLY press "ENTER", then I don't get an answer. If I then keep clicking my "ENTER" button, I don't get replies. I can go on for 10, 20, 30... seconds. But if I wait +/- 10 seconds, and then press "ENTER", then I get my answer "ENTER\n".

So this kind of confirms what I discovered last time. More precisely, if I start communicating with the Arduino just after it is connected, it is entering in a kind of "special mode", and is probably expecting some predefined sequence or protocol. Every time it receives something that is not according to the protocol, it resets its timer and start waiting another 10 seconds. Until it doesn't receive something for 10 seconds, and then it seems to go back to "normal mode", in which it
answers "ENTER\n" if I press the "ENTER" key.

And I can even see this on the LED! When I hit "ENTER" immediately after reconnecting when the LED is on for the first time, the LED remains on for 10 seconds, and then switches OFF. It is like it is stuck in that 'special state', and then it continues.

Conclusions so far: One thing is for sure, if you start communicating with the Arduino while it is starting, it might enter a 'special state'. The only way to get out of this state is waiting at least 10 seconds (communication silence). In most cases, when you open the serial port (and DTR/RTS can indeed avoid that it reboots), you can start communicating after a few seconds. Although, with my C# app that seems to fail very occasionally. The best sequence so far is:

  1. Open the Serial Port
  2. Wait 2 seconds
  3. Start Communicating and see if you get answer
    4.1 If answer is received, all is ok
    4.2 If no answer received, wait at least 10 seconds (I use 12) and go back to 3

I’ve written a small tutorial on interfacing with Python. See Two ways communication between Python3 and Arduino

The way it works is that the arduino sends an OK message in the setup to let the Mac/PC know it’s ready. Could you try the script and see how long it takes ?

That may apply to your Arduino devices but not to those I have ...

Have a look at @J-M-L 's suggestion in post #17.

If it does not help I suggest as follows:

  • Implement a Serial.println() message in setup() that your C# program evaluates to start communcation. That definitely avoids any serial input before end of setup() is reached (See "Start" message in the sketch below)
  • Add a blink without delay to see when your sketch really enters loop() (also implemented in the sketch below). If the MEGA is reset the built-in led will start blinking with 1 Hz (0.5s ON and 0.5s OFF)
/*
  Forum: https://forum.arduino.cc/t/when-connecting-usb-to-my-arduino-i-need-to-wait-10-seconds-before-being-able-to-send-commands/1219902
  Wokwi: https://wokwi.com/projects/388896449664965633

  Sketch from Forum 1:1 except

  - ButtonClass.h which has been written by ec2021 (Original missing in Forum)
  - #include of ButtonClass.h 
 - Sending "Start" via Serial at the end of setup()
- Blinking built-in led in loop()

  2024/02/05
  ec2021

*/

//#include "src/ButtonClass/ButtonClass.h"
#include "ButtonClass.h"

// Command related items
#define CMD_SIZE 100
char sBuffer[CMD_SIZE];
char sCommand[CMD_SIZE];
char* sParameter;
int iRxPtr = 0;
bool bCmdReady = false;
bool bRegistered = false;

// Global variables for Serial communication
const long baudrate = 500000;

// IDENT
const String sIdent = "TEST Module\n";
const String sProcessor = "ARDUINO\n";

// variables (variables start at 001
const char *Variables[] = {
  "FLOAT64_R_A:AUTOPILOT ALTITUDE LOCK VAR:3,feet",     // 001
  "VOID_K:A32NX.FCU_HDG_INC",                           // 002
  "VOID_K:A32NX.FCU_HDG_DEC",                           // 003
  };
size_t nVariables = sizeof(Variables)/sizeof(Variables[0]);

// Easy way to toggle an LED
void ToggleLed(int pin) { digitalWrite(pin, !digitalRead(pin)); }

// Acknowledge
#define ACK Serial.print("A\n")

// Buttons
#define BTN_HDG_INC 40
#define BTN_HDG_DEC 41
ButtonClass bcHDG_INC = ButtonClass(BTN_HDG_INC, 50);
ButtonClass bcHDG_DEC = ButtonClass(BTN_HDG_DEC, 50);

unsigned long lastBlink = 0;
void blink(){
  if (millis()-lastBlink >= 500){
    lastBlink = millis();
    ToggleLed(LED_BUILTIN);
  }
}

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  Serial.begin(baudrate, SERIAL_8N1);
  Serial.println("Start");
}

void loop() {
  blink();
  // put your main code here, to run repeatedly:
  if (bCmdReady) {

    // Process IDENT command
    if (strcmp(sCommand, "IDENT") == 0) {
      Serial.print(sIdent);
      Serial.print(sProcessor);
    }

    // Process REGISTER command
    else if (strcmp(sCommand, "REGISTER") == 0) {
      for (int i = 0; i < nVariables; i++)
      {
        Serial.print(Variables[i]);
        Serial.print("\n");
      }
      Serial.print("\n");
      bRegistered = true;
    }

    else if (bRegistered) {
      // Reset bRegistered flag - do not send ACK
      if (strcmp(sCommand, "RESET") == 0)
      {
        bRegistered = false;
        ToggleLed(LED_BUILTIN);
      }

      else if ((strlen(sCommand) > 4) && (sCommand[3] == '='))
      {
        // Assumed that "NNN=..." is received
        
        ACK;

        sCommand[3] = '\0';
        sParameter = &sCommand[4];

        int iID = atoi(sCommand);
        if (iID != 0)
        {
          switch (iID) {
            case 1: // FLOAT64_R_A:AUTOPILOT ALTITUDE LOCK VAR:3,feet
            {
              ToggleLed(LED_BUILTIN);
              break;
            }
            default:
              break;
          }
        }
      }
    }
    bCmdReady = false;
  }

  if (bRegistered) {
    // Process INC
    if (bcHDG_INC.ButtonState() == OFF_ON) {
      Serial.print("002=1\n"); // VOID_K:A32NX.FCU_HDG_INC
    }
    
    // Process DEC
    if (bcHDG_DEC.ButtonState() == OFF_ON) {
      Serial.print("003=1\n"); // VOID_K:A32NX.FCU_HDG_DEC
    }
  }
}

void serialEvent()
{
  while (Serial.available())
  {
    char cCmd = Serial.read();
    ToggleLed(LED_BUILTIN);
    if (cCmd == '\n')
    {
      sBuffer[iRxPtr] = 0;        // terminate string
      strcpy(sCommand, sBuffer);  // copy sBuffer in sCommand
      bCmdReady = true;           // indicate that command is available
      ToggleLed(LED_BUILTIN);
      iRxPtr = 0;
    }
    else if (cCmd != '\r')
      sBuffer[iRxPtr++] = cCmd;
  }
}

And is there any reason why you do not post your ButtonClass?

Just to make sure that it is not causing any trouble ...

I think that that is correct. That special state would be the bootloader waiting for more data for the upload. If you don't send anything, the bootloader times out after a short period.

Further, when the Arduino goes through a reset, the bootloader flashes the built-in LED. The number of flashes depends on the bootloader. I have a SparkFun RedBoard and the LED flashes a few times (very short ON/OFF) on reset; my Arduino Mega flashes twice and the ON is longer.

@sterretje @ec2021 @J-M-L

First of all, great post @J-M-L ! I implemented the same kind of concept in my code, and it works as a charm. I simply added an acknowledge-sequence ("A\n") at the end of 'setup()', and in my C# app I wait for it before proceeding. When you receive the ACK from the Arduino, you know that the boot cycle has been finished, and you can proceed with your own communication.

#define ACK Serial.print("A\n")

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);

  Serial.begin(baudrate, SERIAL_8N1);
  ACK;
}

To assure that this works, I set my SerialPort.DtrEnable and SerialPort.RtsEnable to true, to guarantee that my Arduino resets (and runs through the 'setup()' when I open my port.

And for Arduino's that would not have implemented this in the 'setup()', I made my SerialPort.ReadTimeout = 2000. This guarantees that the Arduino has time to reboot. The result is that for implementations where the ACK is included in the 'setup()', the initial connection goes a lot faster. In other cases, you lose 2 seconds.

And for the retry, I wait 12 seconds. This is for the very unlikely case that an Arduino would be not yet fully rebooted after 2 seconds, and due to the first communication remains in that "special state" for 10 seconds.

Bottom line, this is in my opinion the perfect solution. At least for Arduino.

I don't use Arduino's in my projects, but I'm using PIC-microcontrollers. DTR/RTS is ignored in my implementation, so it doesn't reboot. That means that there is never an ACK being sent. This means that for my devices, I always will lose 2 seconds. Not a real drama, because even if I connect 20 devices at the same time, all the communication runs asynchronously, which means that in total I only lose 2 seconds. I could also include an "option" to enable or disable the "wait for ACK on start"-feature, but honestly, that would overcomplicate things.

@ec2021 And about the buttonclass. I simply didn't include it, because at the end I had even reduced my code that completely ruled out the buttonclass (it was not used any longer). So it wasn't very relevant for this discussion any longer. But if you are really interested, you can find this on my GitHub link here.