WiFi reconnect is blocking my loop

I’m using the WiFi Esp library, using a ESP8266 to give my uno wifi capability. It’s working fine for posting data to my PC, got a bit of an issue on the receive side but am working around it.

Unfortunately, when I lose WiFi connection it blocks my loop. This is problematic because I’m running relays on timers - sometimes the connection will drop while the relay is energised and it’ll stay that way until it reconnects.

Could anyone suggest where I’ve gone wrong? (apologies, theres a fair chunk of code here)

#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into digital pin 2
#define ONE_WIRE_BUS 5

#include <SPI.h>
#include "WiFiEsp.h"
#include "SoftwareSerial.h"
#ifndef HAVE_HWSERIAL1
#include <PubSubClient.h>
#include "IPAddress.h"
#include "certs.h"
SoftwareSerial Serial1(4,7); // RX, TX
#endif



//setup a onewire instance to communicate with any OneWire device
OneWire oneWire(ONE_WIRE_BUS);

//pass oneWire reference to DallasTemperature library
DallasTemperature sensors(&oneWire);
// Update these with values suitable for your hardware/network

int status = WL_IDLE_STATUS;     // the Wifi radio's status
const int fanPin = 11;



WiFiEspClient WiFiclient;
PubSubClient client(WiFiclient);


const int relayPin_1 = 9;         //relay output pins
const int relayPin_2 = 10;

long lastReconnectAttempt = 0;
long lastClientLoop = 0;

char pressureData[10];
char tempCStr[10];
int pressureVal;
double pressureBar;
const int pressureSensor = A0;


unsigned long previousPressureMillis = 0;
unsigned long currentMillis = 0;
unsigned long currentMillis_1 = 0;
unsigned long currentMillis_2 = 0;
unsigned long previousRelayMillis_1 = 0;
unsigned long previousRelayMillis_2 = 0;
const int pressureDataDelay = 500;
unsigned long relayInterval = 30000;
const int relayRunTime_1 = 2000;
const int relayRunTime_2 = 1000;
unsigned long tester = 7000;
unsigned long previousTempMillis = 0;


byte relayState_1 = HIGH;   //  for keeping track of ON/OFF
byte relayState_2 = HIGH;


int deviceCount = 0;
const long interval = 5000;
float tempC;

const char* temps[] = {"temps1", "temps2", "temps3", "temps4"};



void setup()
{
   // initialize serial for debugging
  Serial.begin(115200);
  // initialize serial for ESP module
 Serial1.begin(9600);
  // initialize ESP module
  WiFi.init(&Serial1);


  // check for the presence of the shield
  if (WiFi.status() == WL_NO_SHIELD) {
   Serial.println("WiFi shield not present");
    // don't continue
    while (true);
  }

  // attempt to connect to WiFi network
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network
    status = WiFi.begin(ssid, pass);
  }

  Serial.println("You're connected to the network");
  
  pinMode(fanPin, OUTPUT);
  pinMode(relayPin_1, OUTPUT);        //configuring relay pins
  pinMode(relayPin_2, OUTPUT);
  analogWrite(fanPin, 150);
  
  deviceCount = sensors.getDeviceCount();
  sensors.begin();
  client.setServer(server, 1883);
  client.setCallback(callback);
  client.setKeepAlive( 90 );
  lastReconnectAttempt = 0;
  
}


void loop()
{

  currentMillis = millis();
  currentMillis_1 = millis();
  currentMillis_2 = (currentMillis_1 + relayInterval/2 + relayRunTime_1 - relayRunTime_2);

  if (!client.connected()) {
    long currentMillis = millis();
    if (currentMillis - lastReconnectAttempt > 5000) {
      lastReconnectAttempt = currentMillis;
      // Attempt to reconnect
      if (reconnect()) {
        lastReconnectAttempt = 0;
      }
    }
  } else {
    // Client connected
    client.loop();
  }
  sendTempData();
  sendPressureData();
  updateRelayState_1();
  updateRelayState_2();
  switchRelays();
}



void callback(char* topic, byte *payload, unsigned int length) {


/* if (topic == "interval") {
  char buffer [256];
  interval = strtoul(buffer, 256, payload);
  client.publish("interval", "Interval updated");
  Serial.print("Current Interval Value: ");
  Serial.println(interval);
} */
unsigned long intervalLong;
  byte* p = (byte*)malloc(length);
  // Copy the payload to the new buffer
  memcpy(p,payload,length);
  client.publish("outputs", p, length);
  intervalLong = strtoul(p, NULL, 10);
  relayInterval = intervalLong;
 // Serial.print("Interval is: ");
 // Serial.println(relayInterval);
 // Serial.print("Tester: ");
 // Serial.println(tester);
  // Free the memory
  free(p);
}

boolean reconnect() {

  if (client.connect("arduinoClient")) {
    // Once connected, publish an announcement...
    client.publish("outputs","hello world");
    // ... and resubscribe
    client.subscribe("inputs", 1);
    client.subscribe("interval", 1);
  }
  return client.connected();
}


double mapf(double x, double in_min, double in_max, double out_min, double out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}


void sendPressureData() {
  pressureVal =  848;           //    analogRead(pressureSensor);
  pressureBar = mapf(pressureVal, 175, 900, 0.0, 10.00);
  dtostrf(pressureBar, 4, 2, pressureData);
  if (currentMillis - previousPressureMillis >= pressureDataDelay) {
    client.publish("pressureData", pressureData);
 //    Serial.print("Interval: ");
    // Serial.println(interval);
  previousPressureMillis = currentMillis;
  }
}




void sendTempData() {
  // send the command to get temperatur;
 if (currentMillis - previousTempMillis >= interval) {
  sensors.requestTemperatures();
  

  for(int i = 0; i < 4; i++) {
    tempC = sensors.getTempCByIndex(i);
    dtostrf(tempC, 4, 2, tempCStr);
   client.publish(temps[i], tempCStr);
  }
  previousTempMillis = currentMillis;
//  Serial.println("");
 }
}

void updateRelayState_1() {

  if (relayState_1 == HIGH) {
    if (currentMillis_1 - previousRelayMillis_1 >= relayInterval) {
      relayState_1 = LOW;
      previousRelayMillis_1 += relayInterval;
    } 
  } else {
      if (currentMillis_1 - previousRelayMillis_1 >= relayRunTime_1) {
        relayState_1 = HIGH;
        previousRelayMillis_1 += relayRunTime_1;
      }
  }
}

void updateRelayState_2() {

  if(relayState_2 == HIGH) {
    if(currentMillis_2 - previousRelayMillis_2 >= relayInterval) {
      relayState_2 = LOW;
      previousRelayMillis_2 += relayInterval;
    }
  } else {
    if (currentMillis_2 - previousRelayMillis_2 >= relayRunTime_2) {
      relayState_2 = HIGH;
      previousRelayMillis_2 += relayRunTime_2;
    }
  }
}

void switchRelays() {

  digitalWrite(relayPin_1, relayState_1);
  digitalWrite(relayPin_2, relayState_2);
  
}

Bump for visibility.

trojanhawrs:
Bump for visibility.

You may not be getting responses because using an ESP8266 to give an Uno wifi capability is bizarre.

I think I've seen two posts about this combination in the past few months, and I don't know the status of those projects.

But, I'll tell you what I told those posters. If you need WiFi, why not use a board that already has WiFi? My go-to board is the Wemos D1 Mini, and if I need more I/O pins, the NodeMCU.

I’m not sure it’s bizarre. The fact there is a library for it, and ESP8266 modules available, seem to indicate it isn’t at all bizarre!

I even have a ESP8266 module, although my end goal is to add it to a PIC micro and not an Arduino.

My guess is…

 WiFi.begin(ssid, pass);

…is a blocking function in the library.

There’s probably not a good reason for that, other than the library writer didn’t think it necessary to code it as non-blocking.

Solutions would be find another library, or fix the one you are using.

pcbbc:
I’m not sure it’s bizarre. The fact there is a library for it, and ESP8266 modules available, seem to indicate it isn’t at all bizarre!

I even have a ESP8266 module, although my end goal is to add it to a PIC micro and not an Arduino.

My guess is....

client.connect;

..is a blocking function in the library.

There’s probably not a good reason for that, other than the library writer didn’t think it necessary to code it as non-blocking.

Solutions would be find another library, or fix the one you are using.

pcbbc:
My guess is…

 WiFi.begin(ssid, pass);

…is a blocking function in the library.

There’s probably not a good reason for that, other than the library writer didn’t think it necessary to code it as non-blocking.

Solutions would be find another library, or fix the one you are using.

Do you think it’s the ESP function, the MQTT or both? Could connect be calling to both libraries and causing some kind of conflict?

trojanhawrs:
Do you think it's the ESP function, the MQTT or both? Could connect be calling to both libraries and causing some kind of conflict?

Sorry I corrected my original post as it looks like it is probably client.connect() in reconnect() that is doing the blocking, and not WiFi.begin().

Have you tried calling WiFi.status() before client.connect()?
Probably not worth trying to connect unless you get WL_CONNECTED.

That’s about the only thing I can think of doing in your code.

pcbbc:
My guess is....

 WiFi.begin(ssid, pass);

..is a blocking function in the library.

Doesn't matter if it is. The OP said his loop() is blocked and WiFiBegin() is in the setup().

OP- how do you know you loop is blocked? Are you getting a WDT restart?

SteveMann:
Doesn't matter if it is. The OP said his loop() is blocked and WiFiBegin() is in the setup().

OP- how do you know you loop is blocked? Are you getting a WDT restart?

I've never seen that in the serial, as far as I can tell all that is happenning is it's losing WiFi - the power LED stays lit but the blue LED goes off (its pretty much constantly flashing in normal operation).

I know the loop is blocked because my timers get thrown off and I get a "hello world" message to my MQTT broker indicating that reconnect() has been called. I'll only get that at startup when I'm by my PC in stronger signal

SteveMann:
Doesn't matter if it is. The OP said his loop() is blocked and WiFiBegin() is in the setup().

Yes, did you not see I corrected my original post? As I mentioned in post #6.
Unfortunately the OP had already quoted me, and now you’ve required hin from before my correction.

Well, I've ordered myself a WeMos D1 mini to see if I have any more luck. Less than a tenner for the board and 2 proto shields so cant really complain.

Looks like it has a 5V input, presumably it regulates down to 3.3? Are the outputs 3.3 and will they be able to activate my 5V relay module (ill obviously power it via the 5V supply)?

Yes, the Wemos D1 Mini is a 3v3 device. You didn't say (or I didn't see) which relay you are using, but if it's a relay module with a data pin for control and separate power for the coils, (Vcc, Ground and In), then the Wemos should work with it.

It's a 4-channel job, and yeah it uses optocouplers.

Looks like I'm going to have to go that route anyway, just bricked the Uno. Think I shorted 24v to ground, blew the 3v3 regulator and the ESP, the arduino is turning on but the RX/TX are permanently lit and its not being recognized by the COM port.

Might make a nice addition to the mantlepiece. . .