ATWINC1500 with WiFi101 with MQTT always leads to a dead connection after some time

Hi everyone,

I am writing a tool on an Arduino Mega (Controllino MAXI is the exact hardware because it has builtin relays) that simply allows me to open and close windows using relays.

Additionally the Controllino should send and receive MQTT topics/commands to monitor and modify the state of the windows.

Now the problem with the Controllino is that it does not have wireless capability. So I started looking at different solutions to this problem and had to discard quite a number of them because of low connection speeds.

I found the Adafruit ATWINC1500 and it seemed like a good fit for my case, enabling wireless on the controllino.

The project had worked on wire flawlessly. After converting it to wireless the connection kept dropping out after a couple of days. So I added quite a number of debug logging via serial.

I kept adding error handling and recovery into the programming but now I am at a loss what the root cause of the problems is.

So the latest code shows this logging info:

...
04:29:00.527 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:29:05.554 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:29:05.554 -> MQTT publish {"DF_K_Auto":0,"DF_K_Auto_Timer":0,"DF_E_Auto":0,"DF_E_Auto_Timer":0,"RSSI":-39}
04:29:10.550 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:29:15.523 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:29:15.566 -> MQTT publish {"DF_K_Auto":0,"DF_K_Auto_Timer":0,"DF_E_Auto":0,"DF_E_Auto_Timer":0,"RSSI":-39}
04:30:28.030 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:30:28.080 -> MQTT connection has gone offline!
04:30:28.080 -> mqtt trying connection
04:30:48.054 -> Connection to MQTT failed, returnCode: 0 LWMQTT_CONNECTION_ACCEPTED // lastError: -3 LWMQTT_NETWORK_FAILED_CONNECT
04:30:48.097 -> MQTT Reconnect Interval set to: 60000
04:30:48.097 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:30:53.069 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
<snip>
04:31:38.101 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:31:43.080 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:31:48.053 -> No MQTT connection and Reconnect Interval has expired
04:31:48.098 -> mqtt trying connection
04:32:08.074 -> Connection to MQTT failed, returnCode: 0 LWMQTT_CONNECTION_ACCEPTED // lastError: -3 LWMQTT_NETWORK_FAILED_CONNECT
04:32:08.074 -> MQTT Reconnect Interval set to: 120000
04:32:08.074 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:32:13.100 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
<snip>
04:33:58.130 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:34:03.093 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:34:08.085 -> No MQTT connection and Reconnect Interval has expired
04:34:08.085 -> mqtt trying connection
04:34:28.102 -> Connection to MQTT failed, returnCode: 0 LWMQTT_CONNECTION_ACCEPTED // lastError: -3 LWMQTT_NETWORK_FAILED_CONNECT
04:34:28.102 -> MQTT Reconnect Interval set to: 180000
04:34:28.102 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:34:33.079 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
<snip>
04:37:18.118 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:37:23.112 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:37:28.098 -> No MQTT connection and Reconnect Interval has expired
04:37:28.098 -> mqtt trying connection
04:37:48.113 -> Connection to MQTT failed, returnCode: 0 LWMQTT_CONNECTION_ACCEPTED // lastError: -3 LWMQTT_NETWORK_FAILED_CONNECT
04:37:48.113 -> MQTT Reconnect Interval set to: 240000
04:37:48.113 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:37:53.105 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
<snip>
04:41:38.132 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:41:43.158 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:41:48.092 -> No MQTT connection and Reconnect Interval has expired
04:41:48.092 -> mqtt trying connection
04:42:08.114 -> Connection to MQTT failed, returnCode: 0 LWMQTT_CONNECTION_ACCEPTED // lastError: -3 LWMQTT_NETWORK_FAILED_CONNECT
04:42:08.114 -> MQTT Reconnect Interval set to: 300000
04:42:08.114 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:42:13.117 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
<snip>
04:46:58.145 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:47:03.165 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):-39 dBm
04:47:08.108 -> No MQTT connection and Reconnect Interval has expired
04:47:08.108 -> mqtt trying connection
04:47:28.116 -> Connection to MQTT failed, returnCode: 0 LWMQTT_CONNECTION_ACCEPTED // lastError: -3 LWMQTT_NETWORK_FAILED_CONNECT
04:47:28.116 -> Max MQTT interval reached -> disconnecting WiFi to trigger WiFi reconnect
04:47:28.116 -> MQTT Reconnect Interval set to: 300000
04:47:28.116 -> SSID: My_Wifi_SSID, IP Address: 192.168.1.104, Gateway IP Address: 192.168.1.1, WiFi status: 3 WL_CONNECTED, signal strength (RSSI):0 dBm
04:47:29.127 -> Wifi connection has gone offline!
04:47:29.127 -> Attempting to connect to SSID: My_Wifi_SSID
04:48:29.112 -> Connection to Wifi failed, state: 0
04:48:29.112 -> Wifi Reconnect Interval set to: 60000
04:48:29.112 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 0 WL_IDLE_STATUS, signal strength (RSSI):-100 dBm
04:48:34.147 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 0 WL_IDLE_STATUS, signal strength (RSSI):-100 dBm
<snip>
04:49:19.157 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 0 WL_IDLE_STATUS, signal strength (RSSI):-100 dBm
04:49:24.147 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 0 WL_IDLE_STATUS, signal strength (RSSI):-100 dBm
04:49:29.147 -> No Wifi connection and Reconnect Interval has expired, state: 0
04:49:29.147 -> Attempting to connect to SSID: My_Wifi_SSID
04:50:29.141 -> Connection to Wifi failed, state: 0
04:50:29.141 -> Wifi Reconnect Interval set to: 120000
04:50:29.141 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 0 WL_IDLE_STATUS, signal strength (RSSI):-100 dBm
04:50:34.150 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 0 WL_IDLE_STATUS, signal strength (RSSI):-100 dBm
<snip>
04:52:19.160 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 0 WL_IDLE_STATUS, signal strength (RSSI):-100 dBm
04:52:24.173 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 0 WL_IDLE_STATUS, signal strength (RSSI):-100 dBm
04:52:29.141 -> No Wifi connection and Reconnect Interval has expired, state: 0
04:52:29.141 -> Attempting to connect to SSID: My_Wifi_SSID
04:53:29.112 -> Connection to Wifi failed, state: 0
04:53:29.112 -> Wifi Reconnect Interval set to: 180000
04:53:29.158 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 0 WL_IDLE_STATUS, signal strength (RSSI):-100 dBm
04:53:34.117 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 0 WL_IDLE_STATUS, signal strength (RSSI):-100 dBm
<snip>
04:56:19.182 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 0 WL_IDLE_STATUS, signal strength (RSSI):-100 dBm
04:56:24.178 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 0 WL_IDLE_STATUS, signal strength (RSSI):-100 dBm
04:56:29.144 -> No Wifi connection and Reconnect Interval has expired, state: 0
04:56:29.144 -> Attempting to connect to SSID: My_Wifi_SSID
04:56:30.450 -> Connection to Wifi failed, state: 4
04:56:30.450 -> Wifi Reconnect Interval set to: 240000
04:56:30.450 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 4 WL_CONNECT_FAILED, signal strength (RSSI):-100 dBm
04:56:35.420 -> SSID: , IP Address: 0.0.0.0, Gateway IP Address: 0.0.0.0, WiFi status: 4 WL_CONNECT_FAILED, signal strength (RSSI):-100 dBm
...

So basically what is happening is the MQTT connection notices that the connection is down and tries to reconnect. Starting with a 1 min interval increasing to up to 5 min but gets no connection.
After the 5 min interval is reached it disconnects the Wifi to reconnect Wifi in order to get things going again.

But this just ends in the Wifi connection not being able to reconnect.

When this happens the LED on the ATWINC1500 has turned off.

So it appears like the ATWINC1500 is dead. I tried reconnecting the EN(able) PIN and also the Vin but this doesnt heal the problem (probably because after power cycle the ATWINC1500 is not initialized...)

So really now I am wondering what is the problem here?

Is there some sort of a timer drift or other clock related issue (millis() flowing over?) and after a while the connection on the SPI to the ATWINC1500 dies?

I also thought maybe it is a power source issue? But there are 4.9V on the Controllino PINs feeding the board. Could it be a amperage problem? Controllino states a max of: "Absolute max per pin 40mA, recommended 20mA, Absolute max 200mA for entire Pin Header"

So when the error happens i simply reconnect my USB cable for the serial console connection which in turn restarts the Controllino and everything works flawlessly again.

Does anyone have any idea what the root cause could be? Any troubleshooting tips?

Here is the code:

windowctrl.h:

#include <Controllino.h>
#include <limits.h>
#include <WiFi101.h>                       // https://github.com/arduino-libraries/WiFi101 (0.16.1)
#include <driver/source/nmasic.h>
#include <MQTT.h>                          // https://github.com/256dpi/arduino-mqtt (2.5.1)
#include <ArduinoJson.h>                   // https://github.com/bblanchon/ArduinoJson (6.21.3)

#define WIFI_HOSTNAME "ctrlino_df_wifi"  // the hostname the wifi sends to the AP
#define WIFI_SSID     "My_Wifi_SSID"    // your network SSID (name)
#define WIFI_PASSWORD "mypassword"    // your network password (use for WPA, or use as key for WEP)

#define WIFI_RECONNECT_MIN_INTERVAL		(1*60*1000UL) // starting reconnect interval
#define WIFI_RECONNECT_STEP_INTERVAL	(1*60*1000UL) // increase interval after failed attempt
#define WIFI_RECONNECT_MAX_INTERVAL		(5*60*1000UL) // max reconnect interval

#define WIFI_PRINT_INTERVAL 5000 // milliseconds

#define MQTT_HOST        "mqtt.host.local"
#define MQTT_CLIENT_NAME "controllino_mega_df"
#define MQTT_USER        "mosquitto"
#define MQTT_PASSWORD    "mypassword"

#define MQTT_RECONNECT_MIN_INTERVAL		(1*60*1000UL) // starting reconnect interval
#define MQTT_RECONNECT_STEP_INTERVAL	(1*60*1000UL) // increase interval after failed attempt
#define MQTT_RECONNECT_MAX_INTERVAL		(5*60*1000UL) // max reconnect interval

#define MQTT_PUBLISH_INTERVAL 10000 // milliseconds
//#define MQTT_PUBLISH_LEGACY

#define MQTT_PRJ_PREFIX "controllino/DF"
#define MQTT_PATH(x) MQTT_PRJ_PREFIX "/" x
#define MQTT_PATH_DYN(x) (String(MQTT_PRJ_PREFIX "/") + x)

#ifdef DEBUG
 #define DEBUG_PRINT(x) Serial.print(x)
 #define DEBUG_PRINTLN(x) Serial.println(x)
 #define DEBUG_PRINTDECLN(x) Serial.println(x, DEC)
#else
 #define DEBUG_PRINT(x)
 #define DEBUG_PRINTLN(x)
 #define DEBUG_PRINTDECLN(x)
#endif

bool isStrANumber(String str){
  if (str.length() == 0)
    return false;
  
  for(int i=0; i < str.length(); i++)
  {
    if (!isDigit(str[i]))
      return false;
  }
  
  return true;
}

#ifdef DEBUG
// Macro to define an enum-to-string mapping
#define MYENUM_STRING_MAPPING(enum_val) \
    case enum_val: return #enum_val;

// Function to convert enum values to strings
const char* returnCodeToString(int value) {
  switch (value) {
    MYENUM_STRING_MAPPING(LWMQTT_CONNECTION_ACCEPTED)
    MYENUM_STRING_MAPPING(LWMQTT_UNACCEPTABLE_PROTOCOL)
    MYENUM_STRING_MAPPING(LWMQTT_IDENTIFIER_REJECTED)
    MYENUM_STRING_MAPPING(LWMQTT_SERVER_UNAVAILABLE)
    MYENUM_STRING_MAPPING(LWMQTT_BAD_USERNAME_OR_PASSWORD)
    MYENUM_STRING_MAPPING(LWMQTT_NOT_AUTHORIZED)
    MYENUM_STRING_MAPPING(LWMQTT_UNKNOWN_RETURN_CODE)
    default:
      return "Unknown";
  }
}

// Function to convert enum values to strings
const char* lastErrorToString(int value) {
  switch (value) {
    MYENUM_STRING_MAPPING(LWMQTT_SUCCESS)
    MYENUM_STRING_MAPPING(LWMQTT_BUFFER_TOO_SHORT)
    MYENUM_STRING_MAPPING(LWMQTT_VARNUM_OVERFLOW)
    MYENUM_STRING_MAPPING(LWMQTT_NETWORK_FAILED_CONNECT)
    MYENUM_STRING_MAPPING(LWMQTT_NETWORK_TIMEOUT)
    MYENUM_STRING_MAPPING(LWMQTT_NETWORK_FAILED_READ)
    MYENUM_STRING_MAPPING(LWMQTT_NETWORK_FAILED_WRITE)
    MYENUM_STRING_MAPPING(LWMQTT_REMAINING_LENGTH_OVERFLOW)
    MYENUM_STRING_MAPPING(LWMQTT_REMAINING_LENGTH_MISMATCH)
    MYENUM_STRING_MAPPING(LWMQTT_MISSING_OR_WRONG_PACKET)
    MYENUM_STRING_MAPPING(LWMQTT_CONNECTION_DENIED)
    MYENUM_STRING_MAPPING(LWMQTT_FAILED_SUBSCRIPTION)
    MYENUM_STRING_MAPPING(LWMQTT_SUBACK_ARRAY_OVERFLOW)
    MYENUM_STRING_MAPPING(LWMQTT_PONG_TIMEOUT)
    default:
      return "Unknown";
  }
}

// Function to convert enum values to strings
const char* wifiStatusToString(int value) {
  switch (value) {
    MYENUM_STRING_MAPPING(WL_NO_SHIELD)
    MYENUM_STRING_MAPPING(WL_IDLE_STATUS)
    MYENUM_STRING_MAPPING(WL_NO_SSID_AVAIL)
    MYENUM_STRING_MAPPING(WL_SCAN_COMPLETED)
    MYENUM_STRING_MAPPING(WL_CONNECTED)
    MYENUM_STRING_MAPPING(WL_CONNECT_FAILED)
    MYENUM_STRING_MAPPING(WL_CONNECTION_LOST)
    MYENUM_STRING_MAPPING(WL_DISCONNECTED)
    MYENUM_STRING_MAPPING(WL_AP_LISTENING)
    MYENUM_STRING_MAPPING(WL_AP_CONNECTED)
    MYENUM_STRING_MAPPING(WL_AP_FAILED)
    MYENUM_STRING_MAPPING(WL_PROVISIONING)
    MYENUM_STRING_MAPPING(WL_PROVISIONING_FAILED)
    default:
      return "Unknown";
  }
}
#endif

windowctrl.c:

// uncomment when finished!
#define DEBUG
#include "windowctrl.h"

unsigned long lastWifiPrint = 0;
unsigned long curWifiReconnectInterval = WIFI_RECONNECT_MIN_INTERVAL;
bool isWifiOffline = true;
unsigned long lastWifiConnectionAttempt = 0;

WiFiClient wifi_client;
MQTTClient mqttClient(512);   // max buffer size for tx/recv

bool publishMQTTthisLoop = false;
unsigned long lastMQTTpublish = 0;
unsigned long curMQTTreconnectInterval = MQTT_RECONNECT_MIN_INTERVAL;
bool isMQTToffline = true;
unsigned long lastMQTTconnectionAttempt = 0;

const int NUM_WINDOWS = 2; // number of windows to control

const unsigned long STD_HOLD_OPENTIME = 5*60*1000UL;  // time to leave window open
const unsigned long STD_USR_BUTTON_HOLD_TIME = 750;  // how long does a user have to hold button for function to work
const unsigned long STD_USR_BUTTON_CONTINUED_HOLD_TIME = 500;  // how long does a user have to hold button for additional blinks
const unsigned long STD_SEND_KEYPRESS_TIME = 200;  // how long should keypresses be sent on wire

const unsigned long DEBOUNCE_DELAY = 50;  // the debounce time; increase if the input flickers

int pin_input[NUM_WINDOWS] = { CONTROLLINO_A0, CONTROLLINO_A1 };  // input pins
int pin_led[NUM_WINDOWS] = { CONTROLLINO_D0, CONTROLLINO_D1 };    // LED Pins
int pin_open[NUM_WINDOWS] = { CONTROLLINO_R0, CONTROLLINO_R2 };   // open command
int pin_close[NUM_WINDOWS] = { CONTROLLINO_R1, CONTROLLINO_R3 };  // close command

int lastButtonState[NUM_WINDOWS] = { LOW, LOW };
int buttonState[NUM_WINDOWS] = { LOW, LOW };
unsigned long lastDebounceTime[NUM_WINDOWS] = { ULONG_MAX, ULONG_MAX };  // the last time the input pin was toggled
unsigned long debounceDelay[NUM_WINDOWS] = { DEBOUNCE_DELAY, DEBOUNCE_DELAY };    // the debounce time; increase if the input flickers
unsigned long lastButtonHoldTime[NUM_WINDOWS] = { ULONG_MAX, ULONG_MAX };  // the last time the input pin was being held
unsigned long buttonHoldDelay[NUM_WINDOWS] = { STD_USR_BUTTON_HOLD_TIME, STD_USR_BUTTON_HOLD_TIME };    // the button hold time; after this ms a button function for hold in activated
unsigned long buttonHoldBlinkDelay[NUM_WINDOWS] = { STD_USR_BUTTON_CONTINUED_HOLD_TIME, STD_USR_BUTTON_CONTINUED_HOLD_TIME };    // the continued button hold time; after this ms the next blink/step is activated
unsigned long buttonHoldBlinksDone[NUM_WINDOWS] = { 0, 0 };    // number of times we have blinked the LED to the user

unsigned long f3Delay[NUM_WINDOWS] = { STD_SEND_KEYPRESS_TIME, STD_SEND_KEYPRESS_TIME };    // time to hold open
unsigned long f4Delay[NUM_WINDOWS] = { STD_HOLD_OPENTIME, STD_HOLD_OPENTIME };  // time to leave window open
unsigned long f6Delay[NUM_WINDOWS] = { STD_SEND_KEYPRESS_TIME, STD_SEND_KEYPRESS_TIME };    // time to hold close 

enum ventingFunctionStates { // state machine, these functions will be cycled in order
  F1_OFF, // blink disable
  F2_OPENWINDOW_START,
  F3_OPENWINDOW_END,
  F4_WAIT_WINDOW_OPENED,
  F5_CLOSEWINDOW_START,
  F6_CLOSEWINDOW_END,
};
 
enum ventingFunctionStates ventingFunctionState[NUM_WINDOWS];

enum functionList {
  FL_1_K_DACHFENSTER_LUEFTUNG,
  FL_2_E_DACHFENSTER_LUEFTUNG
};

int buttonPushes[NUM_WINDOWS] = { 0, 0 };
boolean ventingFunctionActive[NUM_WINDOWS] = { false, false };
unsigned long f2StartTime[NUM_WINDOWS] = { 0, 0 };  // working variables
unsigned long f3StartTime[NUM_WINDOWS] = { 0, 0 };  // working variables
unsigned long f5StartTime[NUM_WINDOWS] = { 0, 0 };  // working variables
unsigned long ManualOpenStartTime[NUM_WINDOWS] = { 0, 0 };  // working variables
unsigned long ManualCloseStartTime[NUM_WINDOWS] = { 0, 0 };  // working variables
unsigned long lastSerialInfo = 0;
char* mqttName[NUM_WINDOWS] = { "DF_K", "DF_E" };                // mqtt topic Name
char* mqttNameAuto[NUM_WINDOWS] = { "DF_K_Auto", "DF_E_Auto" };  // mqtt topic Name
char* mqttNameAutoTimer[NUM_WINDOWS] = { "DF_K_Auto_Timer", "DF_E_Auto_Timer" }; // mqtt topic Name

void setup() {
  setupSerial();
  setupPins();
  setupWiFi();
  if (WiFi.status() == WL_CONNECTED)
    mqttConnect();
}

// main loop
void loop() {
  CheckAndProcessInput(FL_1_K_DACHFENSTER_LUEFTUNG);
  if (ventingFunctionActive[FL_1_K_DACHFENSTER_LUEFTUNG])
    ContinueVentingFunction(FL_1_K_DACHFENSTER_LUEFTUNG);

  CheckAndProcessInput(FL_2_E_DACHFENSTER_LUEFTUNG);
  if (ventingFunctionActive[FL_2_E_DACHFENSTER_LUEFTUNG])
    ContinueVentingFunction(FL_2_E_DACHFENSTER_LUEFTUNG);

  // do we have a request for manual close/open from mqtt? do it and reset to idle
  for (int nWin=0; nWin<NUM_WINDOWS; nWin++) {
    if (ManualOpenStartTime[nWin]) {
      if ((millis() - ManualOpenStartTime[nWin]) > STD_SEND_KEYPRESS_TIME) {
        digitalWrite(pin_open[nWin], LOW);
        ManualOpenStartTime[nWin] = 0;
      }
    }

    if (ManualCloseStartTime[nWin]) {
      if ((millis() - ManualCloseStartTime[nWin]) > STD_SEND_KEYPRESS_TIME) {
        digitalWrite(pin_close[nWin], LOW);
        ManualCloseStartTime[nWin] = 0;
      }
    }
  }

  ensureWiFiConnection();
  if (WiFi.status() == WL_CONNECTED) {
    mqttEnsureConnection();

    if (mqttClient.connected()) {
      mqttClient.loop();
      publishMQTTValues(); // publish all values to the broker
    }
  }

  printWiFiStatus();
}

void setupSerial() {
  // Initialize serial
#ifdef DEBUG
  Serial.begin(115200);
#endif
  while (!Serial) {
    delay(20); // wait for serial port to connect. Needed for native USB port only
  }
  delay(1000);
}

void setupPins() {
  pinMode(pin_input[FL_1_K_DACHFENSTER_LUEFTUNG], INPUT);
  pinMode(pin_led[FL_1_K_DACHFENSTER_LUEFTUNG], OUTPUT);
  digitalWrite(pin_led[FL_1_K_DACHFENSTER_LUEFTUNG], LOW);

  pinMode(pin_open[FL_1_K_DACHFENSTER_LUEFTUNG], OUTPUT);
  digitalWrite(pin_open[FL_1_K_DACHFENSTER_LUEFTUNG], LOW);
  pinMode(pin_close[FL_1_K_DACHFENSTER_LUEFTUNG], OUTPUT);
  digitalWrite(pin_close[FL_1_K_DACHFENSTER_LUEFTUNG], LOW);

  ventingFunctionState[FL_1_K_DACHFENSTER_LUEFTUNG] = F1_OFF;
//////////////////////////////////////////////////////////////////////
  pinMode(pin_input[FL_2_E_DACHFENSTER_LUEFTUNG], INPUT);
  pinMode(pin_led[FL_2_E_DACHFENSTER_LUEFTUNG], OUTPUT);
  digitalWrite(pin_led[FL_2_E_DACHFENSTER_LUEFTUNG], LOW);

  pinMode(pin_open[FL_2_E_DACHFENSTER_LUEFTUNG], OUTPUT);
  digitalWrite(pin_open[FL_2_E_DACHFENSTER_LUEFTUNG], LOW);
  pinMode(pin_close[FL_2_E_DACHFENSTER_LUEFTUNG], OUTPUT);
  digitalWrite(pin_close[FL_2_E_DACHFENSTER_LUEFTUNG], LOW);

  ventingFunctionState[FL_2_E_DACHFENSTER_LUEFTUNG] = F1_OFF;
}

void setupWiFi()
{
  // Init internal CS pins
  pinMode(CONTROLLINO_RTC_CHIP_SELECT, OUTPUT);
  pinMode(CONTROLLINO_ETHERNET_CHIP_SELECT, OUTPUT);
  digitalWrite(CONTROLLINO_RTC_CHIP_SELECT, LOW);       // inactive
  digitalWrite(CONTROLLINO_ETHERNET_CHIP_SELECT, HIGH); // inactive

  // Set WiFi pins
  WiFi.setPins(53 /* CS */, 20 /* IRQ */, 21 /* RST */);

  // Print a welcome message
  DEBUG_PRINTLN("WiFi101 firmware check.");
  DEBUG_PRINTLN();

  // Check for the presence of the shield
  DEBUG_PRINT("WiFi101 shield: ");
  if (WiFi.status() == WL_NO_SHIELD) {
    DEBUG_PRINTLN("NOT PRESENT");
    while (true) { delay(1000); } // don't continue
  }
  DEBUG_PRINTLN("DETECTED");

  // Print firmware version on the shield
  String fv = WiFi.firmwareVersion();
  String latestFv;
  DEBUG_PRINT("Firmware version installed: ");
  DEBUG_PRINTLN(fv);

  if (REV(GET_CHIPID()) >= REV_3A0) {
    // model B
    latestFv = WIFI_FIRMWARE_LATEST_MODEL_B;
  } else {
    // model A
    latestFv = WIFI_FIRMWARE_LATEST_MODEL_A;
  }

  // Print required firmware version
  DEBUG_PRINT("Latest firmware version available : ");
  DEBUG_PRINTLN(latestFv);

  // Check if the latest version is installed
  DEBUG_PRINTLN();
  if (fv >= latestFv) {
    DEBUG_PRINTLN("Check result: PASSED");
  } else {
    DEBUG_PRINTLN("Check result: NOT PASSED");
    DEBUG_PRINTLN(" - The firmware version on the shield do not match the");
    DEBUG_PRINTLN("   version required by the library, you may experience");
    DEBUG_PRINTLN("   issues or failures.");
  }

  connectWiFi();
}

void connectWiFi() {
  DEBUG_PRINT("Attempting to connect to SSID: ");
  DEBUG_PRINTLN(WIFI_SSID);
  WiFi.hostname(WIFI_HOSTNAME);         // set our own hostname
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD); // Connect to WPA/WPA2 network. Change this line if using open or WEP network

  if (WiFi.status() != WL_CONNECTED) {
    DEBUG_PRINT("Connection to Wifi failed, state: ");
    DEBUG_PRINTLN(WiFi.status());
    isWifiOffline = true;
    lastWifiConnectionAttempt = millis();
  } else {  
    DEBUG_PRINTLN("Connected to wifi");
    isWifiOffline = false;
    if (lastMQTTconnectionAttempt > 0) {
      DEBUG_PRINTLN("triggering mqtt reconnect");
      lastMQTTconnectionAttempt = millis() - MQTT_RECONNECT_MAX_INTERVAL;
    }
  }
}

void ensureWiFiConnection() {
  // attempt to connect to WiFi network:
  if (WiFi.status() == WL_CONNECTED) {
    isWifiOffline = false;
    return;
  }

  // wifi has not been offline but it is now, try to reconnect immediatly
  if (!isWifiOffline) {
    isWifiOffline = true;
    DEBUG_PRINTLN("Wifi connection has gone offline!");
    connectWiFi();
    if (isWifiOffline) {
      curWifiReconnectInterval = WIFI_RECONNECT_MIN_INTERVAL;
      DEBUG_PRINT("Wifi Reconnect Interval set to: ");
      DEBUG_PRINTLN(curWifiReconnectInterval);
    }
    return;
  }

  if ((millis() - lastWifiConnectionAttempt) < curWifiReconnectInterval)
    return;

  DEBUG_PRINT("No Wifi connection and Reconnect Interval has expired, state: ");
  DEBUG_PRINTLN(WiFi.status());

  connectWiFi();
  if (isWifiOffline) {
    curWifiReconnectInterval = min(curWifiReconnectInterval + WIFI_RECONNECT_STEP_INTERVAL, WIFI_RECONNECT_MAX_INTERVAL);
    DEBUG_PRINT("Wifi Reconnect Interval set to: ");
    DEBUG_PRINTLN(curWifiReconnectInterval);
  }
}

void printWiFiStatus() {
  if ((millis() - lastWifiPrint) <= WIFI_PRINT_INTERVAL)
    return;
  lastWifiPrint = millis();

  // print the SSID of the network you're attached to:
  DEBUG_PRINT("SSID: ");
  DEBUG_PRINT(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  DEBUG_PRINT(", IP Address: ");
  DEBUG_PRINT(ip);

  IPAddress gip = WiFi.gatewayIP();
  DEBUG_PRINT(", Gateway IP Address: ");
  DEBUG_PRINT(gip);

  DEBUG_PRINT(", WiFi status: ");
  DEBUG_PRINT(WiFi.status());
  DEBUG_PRINT(" ");
  DEBUG_PRINT(wifiStatusToString(WiFi.status()));

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  DEBUG_PRINT(", signal strength (RSSI):");
  DEBUG_PRINT(rssi);
  DEBUG_PRINTLN(" dBm");
}

void mqttConnect() {
  DEBUG_PRINTLN("mqtt trying connection");

  mqttClient.setTimeout(500); // aggressive Timeout to prevent stalling realtime function of the device.
  mqttClient.begin(MQTT_HOST, wifi_client);

  if (!mqttClient.connect(MQTT_CLIENT_NAME, MQTT_USER, MQTT_PASSWORD)) {
    DEBUG_PRINT("Connection to MQTT failed, returnCode: ");
    DEBUG_PRINT(mqttClient.returnCode());
    DEBUG_PRINT(" ");
    DEBUG_PRINT(returnCodeToString(mqttClient.returnCode()));
    DEBUG_PRINT(" // lastError: ");
    DEBUG_PRINT(mqttClient.lastError());
    DEBUG_PRINT(" ");
    DEBUG_PRINTLN(lastErrorToString(mqttClient.lastError()));
    isMQTToffline = true;
    lastMQTTconnectionAttempt = millis();
  } else {
    DEBUG_PRINTLN("Connected to MQTT");
    //setwill();
    
    mqttClient.onMessage(onMqttMessageReceived);
    for (int i=0; i<NUM_WINDOWS; i++) {
      mqttClient.subscribe(MQTT_PATH_DYN(String(mqttName[i]) + "/command"));
      mqttClient.subscribe(MQTT_PATH_DYN(String(mqttNameAuto[i]) + "/command"));
      mqttClient.subscribe(MQTT_PATH_DYN(String(mqttNameAutoTimer[i]) + "/command"));
    }
    isMQTToffline = false;
  }
}

void mqttEnsureConnection() {
  if (mqttClient.connected()) {
    isMQTToffline = false;
    lastMQTTconnectionAttempt = 0;
    return;
  }

  // mqtt has not been offline but it is now, try to reconnect immediatly
  if (!isMQTToffline) {
    isMQTToffline = true;
    DEBUG_PRINTLN("MQTT connection has gone offline!");
    mqttConnect();
    if (isMQTToffline) {
      curMQTTreconnectInterval = MQTT_RECONNECT_MIN_INTERVAL;
      DEBUG_PRINT("MQTT Reconnect Interval set to: ");
      DEBUG_PRINTLN(curMQTTreconnectInterval);
    }
    return;
  }

  if ((millis() - lastMQTTconnectionAttempt) < curMQTTreconnectInterval)
    return;

  DEBUG_PRINTLN("No MQTT connection and Reconnect Interval has expired");
  mqttConnect();

  if (isMQTToffline) {
    if (curMQTTreconnectInterval >= MQTT_RECONNECT_MAX_INTERVAL) {
      // we have already reached max interval but still can't reach MQTT -> trigger WiFi reconnect
      DEBUG_PRINTLN("Max MQTT interval reached -> disconnecting WiFi to trigger WiFi reconnect");
      WiFi.disconnect();
    }

    curMQTTreconnectInterval = min(curMQTTreconnectInterval + MQTT_RECONNECT_STEP_INTERVAL, MQTT_RECONNECT_MAX_INTERVAL);
    DEBUG_PRINT("MQTT Reconnect Interval set to: ");
    DEBUG_PRINTLN(curMQTTreconnectInterval);
    return;
  }
}

void publishMQTTValues() {
  publishMQTTthisLoop = false;

  if ((millis() - lastMQTTpublish) > MQTT_PUBLISH_INTERVAL) {
    lastMQTTpublish = millis();
    publishMQTTthisLoop = true;
  }

  if (publishMQTTthisLoop && mqttClient.connected()) {
    DynamicJsonDocument json(512); // WARNING: JSON string must not exceed this many characters
    
    for (int i=0; i<NUM_WINDOWS; i++)
    {
      unsigned long autoTimerValue = 0;
      if (ventingFunctionActive[i])
        autoTimerValue = (f4Delay[i] - (millis() - f3StartTime[i])) / 1000 / 60;

#ifdef MQTT_PUBLISH_LEGACY
      mqttClient.publish(MQTT_PATH_DYN(mqttNameAuto[i]), String(ventingFunctionActive[i] ? 1 : 0));
      mqttClient.publish(MQTT_PATH_DYN(mqttNameAutoTimer[i]), String(autoTimerValue));
#endif
      json[mqttNameAuto[i]] = ventingFunctionActive[i] ? 1 : 0;
      json[mqttNameAutoTimer[i]] = autoTimerValue;
    }
    long rssi = WiFi.RSSI();
#ifdef MQTT_PUBLISH_LEGACY
    mqttClient.publish(MQTT_PATH_DYN("RSSI"), String(rssi));
#endif
    json["RSSI"] = rssi;

    String status;
    serializeJson(json, status);
    DEBUG_PRINT("MQTT publish ");
    DEBUG_PRINTLN(status);
    bool bResult = mqttClient.publish(MQTT_PATH("status"), status);

    if (!bResult) {
      DEBUG_PRINTLN("unable to publish MQTT status! disconnecting...");
      mqttClient.disconnect();
    }
  }
}

void onMqttMessageReceived(String &topic, String &payload) {
  // we received a message, print out the topic and contents
  DEBUG_PRINTLN("Received a message with topic '");
  DEBUG_PRINT(topic);
  DEBUG_PRINT("', payload '");
  DEBUG_PRINT(payload);
  DEBUG_PRINTLN("'");

  String cmdSuffix = "/command";
  
  if (topic.endsWith(cmdSuffix)) {
    String cmdPrefix = MQTT_PATH("");
    DEBUG_PRINTLN(topic);
    String topicWithoutPrefix = topic.substring(cmdPrefix.length());
    DEBUG_PRINTLN(topicWithoutPrefix);
    String strWindow = topicWithoutPrefix.substring(0, topicWithoutPrefix.length()-cmdSuffix.length());
    DEBUG_PRINTLN(strWindow);

    payload.toUpperCase();

    int nWin = findMqttByName(strWindow);
    if (nWin != -1) {
      if (payload == "ON" || payload == "1") {
        DEBUG_PRINT("OK! Activating ");
        DEBUG_PRINTLN(mqttName[nWin]);
        digitalWrite(pin_open[nWin], HIGH);
        ManualOpenStartTime[nWin] = millis();
      }
      if (payload == "OFF" || payload == "0") {
        DEBUG_PRINT("OK! Closing ");
        DEBUG_PRINTLN(mqttName[nWin]);
        digitalWrite(pin_close[nWin], HIGH);
        ManualCloseStartTime[nWin] = millis();
      }

      return;
    }

    nWin = findMqttAutoByName(strWindow);
    if (nWin != -1) {
      if (payload == "ON" || payload == "1") {
        DEBUG_PRINT("OK! Activating ");
        DEBUG_PRINTLN(mqttNameAuto[nWin]);
        if (!(ventingFunctionActive[nWin])) {
          StartupVentingFunction(nWin);
        }
      }
      if (payload == "OFF" || payload == "0") {
        DEBUG_PRINT("OK! Closing ");
        DEBUG_PRINTLN(mqttNameAuto[nWin]);
        if (ventingFunctionActive[nWin]) {
          ShutdownVentingFunction(nWin);
        }
      }

      return;
    }

    nWin = findMqttAutoTimerByName(strWindow);
    if (nWin != -1) {
      // ignore timer changes when venting function is not active
      if (ventingFunctionActive[nWin]) {
        if (isStrANumber(payload)) {
          DEBUG_PRINT("OK! Setting Timer for ");
          DEBUG_PRINT(mqttNameAutoTimer[nWin]);
          DEBUG_PRINT(" to ");
          DEBUG_PRINTLN(payload);
          unsigned long num = payload.toInt();
          f4Delay[nWin] = (millis() + (num*60*1000UL)) - f3StartTime[nWin];
        }
      }

      return;
    }

    DEBUG_PRINT("ERROR! window ");
    DEBUG_PRINT(strWindow);
    DEBUG_PRINTLN(" not found!");
    return;
  }
}

void CheckAndProcessInput(int funcNo) {
  int in = digitalRead(pin_input[funcNo]);
    
  if (in != lastButtonState[funcNo]) {
    lastDebounceTime[funcNo] = millis();
  }
    
  if ((millis() - lastDebounceTime[funcNo]) > debounceDelay[funcNo]) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    // state has changed
    if (in != buttonState[funcNo]) {
      buttonState[funcNo] = in;

      if (in == HIGH) {
        DEBUG_PRINT(millis());
        DEBUG_PRINTLN("***state change HIGH***");
        lastButtonHoldTime[funcNo] = millis();
        buttonHoldBlinksDone[funcNo] = 0;
        //digitalWrite(CONTROLLINO_R0, (buttonPushes % 2) ? LOW : HIGH);
      }
      if (in == LOW) {
        DEBUG_PRINT(millis());
        DEBUG_PRINTLN("***state change LOW***");
        // short press
        if (!((millis() - lastButtonHoldTime[funcNo]) > buttonHoldDelay[funcNo])) {
          buttonPushes[funcNo]++;
          
          ToggleVentingFunction(funcNo);
        }
      }
    }
  }
  lastButtonState[funcNo] = in;  

  // check for input button being held
  if (buttonState[funcNo] == HIGH) {
    // long press?
    if ((millis() - lastButtonHoldTime[funcNo]) > buttonHoldDelay[funcNo]) {    
      // hold detected, startup function in case it was started from hold!
      if (!(ventingFunctionActive[funcNo])) {
        StartupVentingFunction(funcNo);
        delay(50); // give user some time to see the LED HIGH change if we want to blink at him right away
      }

      // we have to blink once after buttonHoldDelay and then every buttonHoldBlinkDelay -> check if we have to blink more
      unsigned long numHaveToBlink = GetNumberOfBlinksNeeded((millis() - lastButtonHoldTime[funcNo]), buttonHoldDelay[funcNo], buttonHoldBlinkDelay[funcNo]);
      
      while (buttonHoldBlinksDone[funcNo] < numHaveToBlink) {
        // WARNING: this should be in a state machine: we block program execution for 50ms per blink (should only be one per call) here!
        digitalWrite(pin_led[funcNo], LOW);
        delay(50);
        digitalWrite(pin_led[funcNo], HIGH);

        DEBUG_PRINT(millis());
        DEBUG_PRINTLN("***LONG PRESS BLINK***");

        buttonHoldBlinksDone[funcNo]++;
        // extend delay per blink 1=std, 2=double, 3=triple time, etc...
        f4Delay[funcNo] = STD_HOLD_OPENTIME * numHaveToBlink;
        DEBUG_PRINT(millis());
        DEBUG_PRINT("extending timer to ");
        DEBUG_PRINTDECLN(numHaveToBlink);
      }
    }
  }

  if ((millis() - lastSerialInfo) > 5000) {
    lastSerialInfo = millis();
//    DEBUG_PRINT(millis());
//    DEBUG_PRINT("Number of pushes so far: ");
//    DEBUG_PRINTDECLN(buttonPushes[funcNo]);
  }
}

unsigned long GetNumberOfBlinksNeeded(unsigned long millisElapsedSinceHold, unsigned long holdDelay, unsigned long holdBlinkDelay) {
  int numBlinks = 0;

  if (millisElapsedSinceHold > holdDelay) {
    numBlinks++;
    millisElapsedSinceHold -= holdDelay;
  }

  numBlinks += floor(millisElapsedSinceHold / holdBlinkDelay);

  return numBlinks;
}

void ToggleVentingFunction(int funcNo)
{
  if (ventingFunctionActive[funcNo] == false)
    StartupVentingFunction(funcNo);
  else
    ShutdownVentingFunction(funcNo);
}

void StartupVentingFunction(int funcNo)
{
  if (!(ventingFunctionActive[funcNo])) {
    DEBUG_PRINT(millis());
    DEBUG_PRINTLN("StartupVentingFunction");
    // show via LED that function is active
    digitalWrite(pin_led[funcNo], HIGH);
    ventingFunctionActive[funcNo] = true;
  }
}

void ShutdownVentingFunction(int funcNo)
{
  DEBUG_PRINT(millis());
  DEBUG_PRINTLN("ShutdownVentingFunction");
  ventingFunctionState[funcNo] = F1_OFF;
  ventingFunctionActive[funcNo] = false;

  digitalWrite(pin_led[funcNo], LOW);
  
  digitalWrite(pin_open[funcNo], LOW);
  digitalWrite(pin_close[funcNo], LOW);
}

void ContinueVentingFunction(int funcNo) {
  switch (ventingFunctionState[funcNo])
  {
    case F1_OFF:
      ventingFunctionState[funcNo] = F2_OPENWINDOW_START;
      // fall through
    case F2_OPENWINDOW_START:
      digitalWrite(pin_open[funcNo], HIGH);
      f2StartTime[funcNo] = millis();
      ventingFunctionState[funcNo] = F3_OPENWINDOW_END;
      break;
      
    case F3_OPENWINDOW_END:
      if ((millis() - f2StartTime[funcNo]) > f3Delay[funcNo])
      {
        digitalWrite(pin_open[funcNo], LOW);
        f3StartTime[funcNo] = millis();
        DEBUG_PRINT(millis());
        DEBUG_PRINT(" setting window open start time to ");
        DEBUG_PRINTDECLN(f3StartTime[funcNo]);
        f4Delay[funcNo] = STD_HOLD_OPENTIME;
        ventingFunctionState[funcNo] = F4_WAIT_WINDOW_OPENED;
      }
      break;
      
    case F4_WAIT_WINDOW_OPENED:
      if ((millis() - f3StartTime[funcNo]) > f4Delay[funcNo])
        ventingFunctionState[funcNo] = F5_CLOSEWINDOW_START; // fall through
      else
        break;
      
    case F5_CLOSEWINDOW_START:
      digitalWrite(pin_close[funcNo], HIGH);
      f5StartTime[funcNo] = millis();
      ventingFunctionState[funcNo] = F6_CLOSEWINDOW_END;
      break;
      
    case F6_CLOSEWINDOW_END:
      if ((millis() - f5StartTime[funcNo]) > f6Delay[funcNo])
      {
        digitalWrite(pin_close[funcNo], LOW);
        ShutdownVentingFunction(funcNo);
      }
      break;
  }
}

int findMqttByName(String &name)
{
  return findMqttByName(name.c_str());
}

int findMqttByName(const char* name)
{
  for (int i=0; i<NUM_WINDOWS; i++)
  {
    if (strcmp(mqttName[i], name) == 0)
      return i;
  }

  return -1;
}

int findMqttAutoByName(String &name)
{
  return findMqttAutoByName(name.c_str());
}

int findMqttAutoByName(const char* name)
{
  for (int i=0; i<NUM_WINDOWS; i++)
  {
    if (strcmp(mqttNameAuto[i], name) == 0)
      return i;
  }

  return -1;
}

int findMqttAutoTimerByName(String &name)
{
  return findMqttAutoTimerByName(name.c_str());
}

int findMqttAutoTimerByName(const char* name)
{
  for (int i=0; i<NUM_WINDOWS; i++)
  {
    if (strcmp(mqttNameAutoTimer[i], name) == 0)
      return i;
  }

  return -1;
}

[crossposting to ATWINC1500 with WiFi101 with MQTT always leads to a dead connection after some time · Issue #354 · arduino-libraries/WiFi101 · GitHub]

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.