Change millis() value

You could write a function, say

unsigned long myMillis()
{
    return millis();
}

and use it everywhere you have regular old real millis().

Test that, nothing changes unless you really strapped for time.

Now you can do anything your heart desires with the value it produces.

You could make myMillis() run backwards. You could make it skip 4294957296 milliseconds (2^32 - 10000) and it would roll over ten seconds later.

I appreciate the desire to really thoroughly test your logic around the rollover matter. I understand everyone's total confidence that it can be made not a problem at all, except for timing very very long periods, which probably should be handled differently anyway.

a7

2 Likes

fixed.

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ArduinoOTA.h>
#include <Wire.h>



//WiFi settings
const char* WiFiHostname =  "Gates"; // WiFi Hostname
const char* ssid = "UniFi-HomeKit"; // WiFi name
const char* password =  "*********"; // WiFi password

//MQTT settings
const char* mqttID = "Gates";
const char* mqttServer = "10.10.20.10";
const int mqttPort = 1883;
const char* mqttUser = "********";
const char* mqttPassword = "***********";

const char* OTAHostname =  "Gates"; //OTA Hostname

// constants
const int ledPin = 2;         // the number of the LED pin
const int frontGatePin = 13;  //D5 yellow
const int backGatePin = 14;   //D7 blue


//time constants
const int oneMinute = (1 * 60 * 1000);
const int twentyMinutes = (20 * 60 * 1000);
const int fiveMinutes = (5 * 60 * 1000);
const int tenSeconds = 10000;
const int oneHour = (1 * 60 * 60 * 1000);
const int thirtyMinutes = (1 * 30 * 60 * 1000);
const int backGateOpenTime = 10000;
const int backGateCloseTime = 10000;
const int backGateTransitTime = 30000;

//MILLIS
unsigned long startMillisBlink;
unsigned long currentMillisBlink;

unsigned long startMillisWait;
unsigned long currentMillisWait;

unsigned long startMillisStatus;
unsigned long currentMillisStatus;


WiFiClient espClient;
PubSubClient client(espClient);

void connectToWiFi()
{
  WiFi.hostname(WiFiHostname);
  WiFi.mode(WIFI_STA); //access point mode disabled
  WiFi.begin(ssid, password);
  Serial.println("");
  Serial.print("Connecting to WiFi");

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    ledBlink(100, 1, false);
  }

  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  //Serial.printf("RSSI: %d dBm\n", WiFi.RSSI());
  long rssi = WiFi.RSSI();
  Serial.print("RSSI:");
  Serial.println(rssi);
}


void connectToMQTT()
{
  client.setKeepAlive(tenSeconds); // setting keep alive to 10 seconds
  client.setServer(mqttServer, mqttPort);
  client.setCallback(callback);
  Serial.println("");
  Serial.print("Connecting to MQTT");

  wait(200);
  Serial.print(".");
  wait(200);
  Serial.print(".");
  wait(200);
  Serial.println(".");
  while (!client.connected()) {

    if (client.connect(mqttID, mqttUser, mqttPassword )) {
      Serial.println("Connected to MQTT server");


    } else {
      ledBlink(300, 2, false);
      Serial.println("");
      Serial.print("failed with state ");
      Serial.print(client.state());

    }
  }
}


void OTASetup()
{

  ArduinoOTA.setHostname(OTAHostname);
  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else { // U_FS
      type = "filesystem";
    }

    // NOTE: if updating FS this would be the place to unmount FS using FS.end()
    Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) {
      Serial.println("Auth Failed");
    } else if (error == OTA_BEGIN_ERROR) {
      Serial.println("Begin Failed");
    } else if (error == OTA_CONNECT_ERROR) {
      Serial.println("Connect Failed");
    } else if (error == OTA_RECEIVE_ERROR) {
      Serial.println("Receive Failed");
    } else if (error == OTA_END_ERROR) {
      Serial.println("End Failed");
    }
  });
  ArduinoOTA.begin();
}

void startConnection()
{
  wait(2000);
  //WiFi
  connectToWiFi();
  wait(tenSeconds);
  //MQTT
  connectToMQTT();
  //OTA
  OTASetup();
}


void ledBlink (int delayPeriod, int blinks, bool beep)
{
  bool timeElapsed = false;

  blinks = blinks * 2;
  while (blinks >= 1)
  {
    timeElapsed = false;

    while (timeElapsed == false)
    {
      ArduinoOTA.handle();
      yield();
      client.loop();
      currentMillisBlink = millis();  //get the current "time"
      if (currentMillisBlink - startMillisBlink >= delayPeriod)  //test whether the period has elapsed
      {
        digitalWrite(ledPin, !digitalRead(ledPin));//if so, change the state of the LED.
        timeElapsed = true;
        startMillisBlink = currentMillisBlink;  //IMPORTANT to save the start time of the current LED state.
      }
    }
    blinks--;
  }
}

void wait (int waitTime)
{
  startMillisWait = millis();
  bool timeElapsed = false;
  while (timeElapsed == false)
  {
    ArduinoOTA.handle();
    client.loop();
    yield();
    currentMillisWait = millis();  //get the current time
    if (currentMillisWait - startMillisWait >= waitTime)  //test whether the period has elapsed
    {
      timeElapsed = true;
      startMillisWait = currentMillisWait;  //IMPORTANT
    }
  }
}

void openFrontGate()
{
  digitalWrite(ledPin, LOW);
  Serial.println("");
  Serial.println("Front gate opening");
  client.publish("getCurrentDoorState/FRONTGATE", "Opening");
  wait(1000);
  client.publish("getCurrentDoorState/FRONTGATE", "Open");

  digitalWrite(frontGatePin, LOW);
  wait(500);
  digitalWrite(frontGatePin, HIGH);

  wait(30000);
  client.publish("getTargetDoorState/FRONTGATE", "C"); Serial.println("Front gate targhet: closed");
  client.publish("getCurrentDoorState/FRONTGATE", "Closing"); Serial.println("Front gate closing");

  wait(1000);
  client.publish("getCurrentDoorState/FRONTGATE", "Closed"); Serial.println("Front gate closed");
  digitalWrite(ledPin, HIGH);
}

void openBackGate()
{
  digitalWrite(ledPin, LOW);
  Serial.println("");
  Serial.println("Back gate opening");
  client.publish("getCurrentDoorState/BACKGATE", "Opening");

  //Open Back Gate
  digitalWrite(backGatePin, LOW);
  wait(500);
  digitalWrite(backGatePin, HIGH);

  wait(backGateOpenTime); //Wait until back gate is open
  client.publish("getCurrentDoorState/BACKGATE", "Open");

  wait(backGateTransitTime); //Wait transit time

  client.publish("getTargetDoorState/BACKGATE", "C"); Serial.println("Back Gate targhet: closed");
  client.publish("getCurrentDoorState/BACKGATE", "Closing"); Serial.println("Back Gate closing");

  wait(backGateCloseTime); //Wait until back gate is close
  client.publish("getCurrentDoorState/BACKGATE", "Closed"); Serial.println("Back Gate closed");
  digitalWrite(ledPin, HIGH);

}

void setup() {

  Serial.begin(115200);
  delay(5000);
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the rekay pins as an output:
  pinMode(frontGatePin, OUTPUT);
  pinMode(backGatePin, OUTPUT);
  
  digitalWrite(ledPin, HIGH); //Set the led off
  digitalWrite(frontGatePin, HIGH); //Set the pin off
  digitalWrite(backGatePin, HIGH); //Set the pin off
  
  startConnection();

  client.subscribe("status/GATES");

  client.subscribe("setTargetDoorState/FRONTGATE"); // target state can be OPEN or CLOSED. By default, values of O and C
  //client.subscribe("getTargetDoorState/FRONTGATE"); //current door state can be OPEN, CLOSED, OPENING, CLOSING, STOPPED.
  //client.subscribe("getCurrentDoorState/FRONTGATE"); //By default, these use values of O, C, o, c and S respectively

  client.subscribe("setTargetDoorState/BACKGATE");



  client.publish("status/GATES", "Boot completed");
  client.publish("getCurrentDoorState/FRONTGATE", "C");
  client.publish("getCurrentDoorState/BACKGATE", "C");

  startMillisStatus = millis();  //initial start time

}



void callback(char* topic, byte* payload, unsigned int length)
{
  //Print message
  Serial.print("Message arrived: ");

  Serial.print(topic);
  Serial.print(", ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  
  //Reset the device
  if (strcmp(topic, "status/GATES") == 0)
  {
     if (!strncmp((char *)payload, "RESET", length))
    {
      ESP.restart();
    }
  }
  
  //Open the front gate
  if (strcmp(topic, "setTargetDoorState/FRONTGATE") == 0)
  {

    if (!strncmp((char *)payload, "O", length))
    {
      openFrontGate();
    }
    else
    {
      client.publish("getTargetDoorState/FRONTGATE", "C"); Serial.println("Back Gate closed");
      client.publish("getCurrentDoorState/FRONTGATE", "Closing"); Serial.println("Back Gate closing");
      client.publish("getCurrentDoorState/FRONTGATE", "Closed"); Serial.println("Back Gate closed");

    }
  }

  //Open the back gate
  if (strcmp(topic, "setTargetDoorState/BACKGATE") == 0)
  {

    if (!strncmp((char *)payload, "O", length))
    {
      openBackGate();
    }
    else
    {
      client.publish("getTargetDoorState/BACKGATE", "C"); Serial.println("Back Gate closed");
      client.publish("getCurrentDoorState/BACKGATE", "Closing"); Serial.println("Back Gate closing");
      client.publish("getCurrentDoorState/BACKGATE", "Closed"); Serial.println("Back Gate closed");
    }
  }


  Serial.println("");
}


void loop() {
  client.loop();
  ArduinoOTA.handle();

  //Check connection every FIVE minutes
  currentMillisStatus = millis();  //get the current "time"
  if (currentMillisStatus - startMillisStatus >= fiveMinutes)  //test whether the period has elapsed
  {
    
    if ((WiFi.status() == WL_CONNECTION_LOST) || (WiFi.status() == WL_DISCONNECTED))
    {

      Serial.println("WiFi connection lost, connecting again");
      startConnection();
      client.publish("status/GATES", "WiFi connection lost, connected again");
    }
    
    if (client.connected() == false)
    {
      Serial.println("MQTT connection lost, connecting again");
      connectToMQTT();
      client.publish("status/GATES", "MQTT connection lost, connected again");
    }

    client.publish("getTargetDoorState/FRONTGATE", "C");
    client.publish("getTargetDoorState/BACKGATE", "C"); 
    
    startMillisStatus = currentMillisStatus;  //IMPORTANT
  }


}

So, this is my code. In basically every project I use the same base, essentially it connects to the WiFi and to a MQTT server and wait for a MQTT message to arrive

The loop function just listens to incoming messages and every five minutes checks the connection, when a message arrive the callback() function get executed and based on the topic and payload it performs some actions.

I created some functions to avoid duplicate code and (hopefully) simplify it.

The wait() function allows me to create a delay without blocking the background functions of the ESP8266 and to stay connected to WiFi and the MQTT server. The ledBlink() function has the same principle and allows me to blink the onboard led without duplicating the code.

This is the basis for all my projects, for this project I have added two functions that allow me to open the two gates from my phone. By calling the functions openFrontGate() and openBackGate(), the contacts of two relays are closed which open the two gates, then a fake closing feedback is sent to my mobile phone.

After about two months of operation, the contacts of the two relays no longer close but I receive the messages that the gates are opening (example: client.publish("getCurrentDoorState/FRONTGATE", "Opening");)
These are the only information on the problem that I have been able to find. I hope I was clear and I apologize if I made any mistakes because English is not my native language.

One member left a long time library that uses 64 bit unsigned long long that could time billions of years in millisecond ticks. The sun should go red giant before it rolls over.

contacts corroded?

I don't see a problem at first glance.
This project would run better on a ESP32, then you can use multiple tasks with delay() and forget about millis() and forget about trying to keep all the services running.

If I turn it off and on again it immediately starts working correctly so I don't think it's a hardware problem. I should have mentioned that earlier

1 Like

I found the problem(s) and it wasn't millis().

When the board loses the WiFi connection the code in the loop() should reconnect to the WiFi and to the MQTT server but instead for some reason it was only trying to reconnect to the MQTT server causing an infinite loop becouse it wasn't connected to the WiFi.

I fixed that problem and I added a counter that limits the attempts to connect to both the WiFi and the MQTT server so it should no longer end in an infinite loop.

After I fixed that problem I noticed that I was subscribing to the MQTT topics in the setup() function so when it reconnected it was no longer subscribed

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