Using millis() outside loop

Hello all,

I'm trying to get some webSocket frames from a server, and the way I've setup my sketch this is happening within setup() and not loop(). I need to leave the connection open for a bit so that I receive a few frames and parse the ones of interest, then close it but at the moment I only get the first one. I can't use delay(), so I thought of doing it with millis() but it doesn't change anything, I guess because this can only happen within loop()? Is there another non-blocking way of doing it within setup? I tried moving the whole part of code in loop() but that created new issues I couldn't resolve-the connection would stay open forever. I'm completely inexperienced with coding btw:)

This is the bit in setup:

// run callback when messages are received
  client.onMessage([&](WebsocketsMessage message) 
  {
    String payload = message.data();    //Get the response payload from server
    Serial.println(payload);    //Print request response payload
    const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
    DynamicJsonBuffer jsonBuffer(capacity);
  
   // Parse JSON object
    JsonObject& root = jsonBuffer.parseObject(payload);
    if (!root.success()) {
      Serial.println(F("Parsing failed!"));
      return;
    }
  
    // Decode JSON/Extract values
    Serial.println(F("Response:"));
    Serial.println(root["pixelCount"].as<char*>());
    Serial.println(root["brightness"].as<char*>());
    client.close();     
  }); 

This is the whole sketch:

#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ArduinoJson.h>
#include <ArduinoWebsockets.h>

using namespace websockets;

#include <Wire.h>
#include <Adafruit_INA219.h>

Adafruit_INA219 ina219;

WebsocketsClient client;    //CLIENT

IPAddress local_IP(192, 168, 1, 95);    //SERVER
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

int button = 3;
int auxButtonState = 0;    // temporary variable for reading the button pin status

int period = 4000;
unsigned long time_now = 0;

const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<body>

<h2>PB Websocket Test Page</h2>

<form action="/action_page">
<p>PB Command:<br /><input name="pbcommand" type="text" value="{getConfig:true}" />
<br /><br />

<input type="submit" value="Submit" /></p>


</form> 

</body>
</html>
)=====";

//SSID and Password of your WiFi router
const char* ssid = "COSMOTE-xxx";
const char* password = "xxxx";
const char* hostname = "CurrentSensor";
const char* websockets_server_host = "192.168.1.12"; //Enter server address CLIENT
const uint16_t websockets_server_port = 81; // Enter server port

ESP8266WebServer server(80); //Server on port 80


const int buttonPin = 3;    // the number of the pushbutton pin

int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers



void onEventsCallback(WebsocketsEvent event, String data)    //CLIENT
{
  (void) data;
  
  if (event == WebsocketsEvent::ConnectionOpened) 
  {
    Serial.println("Connnection Opened");
  } 
  else if (event == WebsocketsEvent::ConnectionClosed) 
  {
    Serial.println("Connnection Closed");
  } 
  
}



//===============================================================
// This routine is executed when you open its IP in browser
//===============================================================
void handleRoot() {
 String s = MAIN_page; //Read HTML contents
 server.send_P(200, "text/html", MAIN_page, sizeof(MAIN_page) );
}
//===============================================================
// This routine is executed when you press submit
//===============================================================
void handleForm() {
 String PBCommand = server.arg("pbcommand"); 


// try to connect to Websockets server
  bool connected = client.connect(websockets_server_host, websockets_server_port, "/");
  
  if (connected) 
  {

    client.send(PBCommand);
    Serial.print("PB Command:");
    Serial.println(PBCommand);
        
  } 
  else 
  {
    Serial.println("Not Connected!");
  }
 

 String s = "<a href='/'> Go Back </a>";
 server.send(200, "text/html", s); //Send web page


}



//==============================================================
//                  SETUP
//==============================================================
void setup(void){
  Serial.begin(115200,SERIAL_8N1,SERIAL_TX_ONLY);
  while (!Serial) {
      // will pause Zero, Leonardo, etc until serial console opens
      delay(1);
  }

  Wire.begin(0, 2);

uint32_t currentFrequency;   //INA219

pinMode(button, INPUT);

  WiFi.mode(WIFI_STA);
  WiFi.config(local_IP, gateway, subnet);
  WiFi.hostname(hostname);
  WiFi.begin(ssid, password);     //Connect to your WiFi router
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  //If connection successful show IP address in serial monitor
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println("WiFi");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());  //IP address assigned to your ESP

  server.on("/", handleRoot);      //Which routine to handle at root location
  server.on("/action_page", handleForm); //form action is handled here

  server.begin();                  //Start server
  Serial.println("HTTP server started");


 // run callback when messages are received
  client.onMessage([&](WebsocketsMessage message) 
  {
    String payload = message.data();    //Get the response payload from server
    Serial.println(payload);    //Print request response payload
    const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
    DynamicJsonBuffer jsonBuffer(capacity);
  
   // Parse JSON object
    JsonObject& root = jsonBuffer.parseObject(payload);
    if (!root.success()) {
      Serial.println(F("Parsing failed!"));
      return;
    }
  
    // Decode JSON/Extract values
    Serial.println(F("Response:"));
    Serial.println(root["pixelCount"].as<char*>());
    Serial.println(root["brightness"].as<char*>());
    client.close();     
  });         
 
  // run callback when events are occuring
          client.onEvent(onEventsCallback);

if (! ina219.begin()) {
    Serial.println("Failed to find INA219 chip");
    while (1) { delay(10); }
  }
Serial.println("Measuring voltage and current with INA219 ...");


  
}
//==============================================================
//                     LOOP
//==============================================================
void loop(void){
  server.handleClient();          //Handle client requests


  // let the websockets client check for incoming messages
  if (client.available()) 
  { 
    client.poll();
  }


  float shuntvoltage = 0;
  float busvoltage = 0;
  float current_mA = 0;
  float loadvoltage = 0;
  float power_mW = 0;

  shuntvoltage = ina219.getShuntVoltage_mV();
  busvoltage = ina219.getBusVoltage_V();
  current_mA = ina219.getCurrent_mA();
  power_mW = ina219.getPower_mW();
  loadvoltage = busvoltage + (shuntvoltage / 1000);



// read the state of the switch into a local variable:
   int reading = digitalRead(buttonPin);

   // If the switch changed, due to noise or pressing:
   if (reading != lastButtonState) {
     // reset the debouncing timer
     lastDebounceTime = millis();
   }

   if ((millis() - lastDebounceTime) > debounceDelay) {
     // whatever the reading is at, it's been there for longer
     // than the debounce delay, so take it as the actual current state:

     // if the button state has changed:
     if (reading != buttonState) {
       buttonState = reading;

       // only toggle the LED if the new button state is HIGH
       if (buttonState == LOW) {
         Serial.print("Button Pressed");


// try to connect to Websockets server
  bool connected = client.connect(websockets_server_host, websockets_server_port, "/");
  
  if (connected) 
  {

    client.send("{getConfig:true}");
    Serial.print("PB Command: {getConfig:true}");     
  } 
  else 
  {
    Serial.println("Not Connected!");
  }       
       }
     }

   }

   // save the reading.  Next time through the loop,
   // it'll be the lastButtonState:
   lastButtonState = reading;
      


if((unsigned long)(millis() - time_now) > period){
        time_now = millis();
        Serial.print("Bus Voltage:   "); Serial.print(busvoltage); Serial.println(" V");
  Serial.print("Shunt Voltage: "); Serial.print(shuntvoltage); Serial.println(" mV");
  Serial.print("Load Voltage:  "); Serial.print(loadvoltage); Serial.println(" V");
  Serial.print("Current:       "); Serial.print(current_mA); Serial.println(" mA");
  Serial.print("Power:         "); Serial.print(power_mW); Serial.println(" mW");
  Serial.println("");
        
    }

  
}

Thanks!

Never post wifi login credentials.

The function millis() starts to work as soon as setup starts.

There is something wrong

syntactically

in your code
if I try to autoformat your code by pressing Ctrl-T some lines inside setup stay unindented

I have never had such a problem before. But I guess that your timing does not work as it should has to do with this strange-ness of non-indention

void setup(void){
  Serial.begin(115200,SERIAL_8N1,SERIAL_TX_ONLY);
  while (!Serial) {
      // will pause Zero, Leonardo, etc until serial console opens
      delay(1);
  }

  Wire.begin(0, 2);

uint32_t currentFrequency;   //???? why does this line

pinMode(button, INPUT);   //???? why does this line stay UN-indented after pressing Ctrl-T?????

  WiFi.mode(WIFI_STA);

best regards Stefan

why can't the code have different states, even if just INIT and RUN within loop()?

are you saying you only want to wait so long for the initial msgs? if so, capture a timestamp in setup() or whenever the connection is made and check for the desired time to expire before taking some action, which may be changing state to RUN.

    if ((millis() - timeStamp) > TIMEOUT)
        someAction ();

I have to #define TIMEOUT, correct?

What do I do with timeStamp? I tried all sorts of variations, but the connection stays open forever, I mean that whatever I put within the if statement is disregarded. Any chance you can be more specific with how to setup the code you provided above?

I noticed that as well, I have no idea why though, the code compiles just fine.

when you want to take some delayed action using millis(), use millis() to capture the time (i.e. timestamp) when that occurs, set TIMEOUT to the desired amount of time you want to wait and take the action when the difference between the current time and the capture timestamp exceeds the timeout

I'm sorry, I still don't get it.

Using a millis() example found elsewhere, I do the following:

int period = 4000;
unsigned long time_now = 0;

Then, in loop() the following:

if((unsigned long)(millis() - time_now) > period){
        time_now = millis();
        //Code goes here
        
    }

This code runs fine in loop()

If I use the exact same code in setup() it doesn't.

when do you set time_now? besides initializing it to zero

Unless you provide some kind of looping mechanism in setup(), like a while() maybe, code in setup() is only executed once, since setup() by design is there to set stuff up for the long haul and runs only once.

So the first and only time millis() is encountered, the value returned by millis() is going to be pretty close to zero, since the system has only just fired up and the timer has only just started.

Your code will "run fine", in the sense of doing what it's supposed to do, as advertised....

This makes me recognise that you did not yet know what setup() and loop() are doing

I recommend reading these chapters

I would recommend to read even more in this tutorial

best regards Stefan
Be the change you want to see in the world

I don't, didn't even know I had to. Could you explain what should do please?

I do understand the differences. I don't expect this bit to run on loop, only whenever client.onMessage is called. I'm sure there has to be a way to insert a non-blocking delay in any part of the sketch, I just can't find an example online.

Hi petro,

if you really want help:
do two things:

write in normal words a detailed description of your wanted functionality
This description must go pretty far beyond the description that you have given in your first post

just write down in detail what is happening.

  • open connection
  • first messages comes in: what shall happen?
  • second message comes in : what shall happen?
  • third message comes in: what shall happen?
  • 4th message comes in: what shall happen?

post your latest code-version as complete sketch
You can post code by using this method that adds the code-tags
There is an automatic function for doing this in the Arduino-IDE
just three steps

  1. press Ctrl-T for autoformatting your code
  2. do a rightclick with the mouse and choose "copy for forum"
  3. paste clipboard into write-window of a posting

best regards Stefan

since setup() runs just on time, it's unlikely that the difference between millis() and time_now is > period and that condition doesn't execute. if you want the code in the condition to execute during setup() invoke it unconditionally

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