Save data every 3 second and send an array every 5 minutes

Hi everyone!

I got a sensor that read 3 data (X, Y and Z) every 3 seconds. I'm storing these data in a JSON object and then in a JSON array. After sampling 100 objects (so after 5 minutes) in the array I want to send the array via MQTT to my topic.

I've already tested MQTT, wifi connection and all the other things and they work perfectly (if I don't use the array I can send an object to my topic). The only problem is read the data every 3 second, create an object, save it in an array and then send the array every 5 minutes. I don't know if I'm messing with the order of the for loop and the if statement or with the declaration of the array or maybe with the millis() function.

I know that this may sound not clear but I want to send data every 5 minutes, in order to do so I read data every 3 seconds and collect 100 samples. (The thing is that I want to power up the wifi on my esp every 5 minutes in order to save power consumption)

Hope someone could help

const unsigned long fiveMinutes = 5 * 60 * 1000UL;
unsigned long previous = 0 - fiveMinutes;

//compute the required size
const size_t CAPACITY = JSON_ARRAY_SIZE(100) + 100*JSON_OBJECT_SIZE(3);
//allocate the memory for the document
StaticJsonDocument<CAPACITY> doc;

//MPU
const int MPU = 0x68; // I2C address of the MPU-6050
int16_t AcX, AcY, AcZ;

void loop(){
  //Create an empty array
  JsonArray arr = doc.to<JsonArray>();

  unsigned long currentTime = millis();

  if (currentTime - previous >= fiveMinutes){
    for (int i=0; i<100; i++){

        //MPU reading
        Wire.beginTransmission(MPU);
        Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
        Wire.endTransmission(false);
        Wire.requestFrom(MPU, 14, true); // request a total of 14 registers
        AcX = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
        AcY = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
        AcZ = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)

        //Create a JSON Object
        JsonObject obj = doc.createNestedObject();
        obj["AcX"] = AcX;
        obj["AcY"] = AcY;
        obj["AcZ"] = AcZ;  
        }
        previous += currentTime;
    } 
}

       //MQTT PUBLISHING JSON PACKAGE 
       char mqttData[MQTT_BUFFER];
       serializeJson(doc, mqttData);
       Serial.println(mqttData);
       int ret = client.publish("esp8266/JSON", mqttData);
}//end of loop

I got a sensor that read 3 data (X, Y and Z) every 3 seconds. I'm storing these data in a JSON object and then in a JSON array.

Where in your sketch are you saving the data to the array and how are you doing the 3 second timing ? The for loop seems to execute 100 times with no regard for time

Your stated requirement should be easy to meet with something like this

unsigned long currentTime;
unsigned long startTime;
unsigned long savePeriod = 3000;
byte saveCount;

void setup()
{
  Serial.begin(115200);
  while (!Serial);
}

void loop()
{
  currentTime = millis();
  if (currentTime - startTime >= savePeriod)
  {
    Serial.print(saveCount);
    Serial.println("\tsave data to array");
    startTime = currentTime;
    saveCount++;
  }
  if (saveCount >= 10)   //change to 100 after testing
  {
    Serial.println("power up WiFi and send data via MQTT");
    saveCount = 0;
  }
}
       //MQTT PUBLISHING JSON PACKAGE

char mqttData[MQTT_BUFFER];
      serializeJson(doc, mqttData);
      Serial.println(mqttData);
      int ret = client.publish("esp8266/JSON", mqttData);

Why is this outside loop() ? Would it be possible to post complete code so some of us might be able to compile it? I don't have an ESP so can't do it.

If you want to turn the WIFI off on a ESP32 you'll want to put the ESP32 into a deep sleep. During deeps sleep the main cores of the main CPU and its peripherals will be off. During sleep time the ULP, the other processor on the ESP32, can be programed to take the readings. After 5 minutes the main CPU can be woken and the created package can be sent.

Your first issue will be programming the ESP32's ULP processor in assembler.

Your next issue will be MQTT message size.

Show the code with your best attempts, describe what the code is supposed to do and what the code is doing.

The ESP32 has its own timers that are a bit more accurate then using the Arduino function millis(). I use esp_timer_get_time() and vTaskDelayUntil( &xLastWakeTime, xFrequency ) as non-blocking delaying mechanisms; esp_timer_get_time() rolls over after 200+ years.

Here is an example code using two methods of millis() like non-blocking delays.

void fDoMoistureDetector( void * parameter )
{
  //wait for a mqtt connection
  while ( !MQTTclient.connected() )
  {
    vTaskDelay( 250 );
  }
  int      TimeToPublish = 5000000; //5000000uS
  int      TimeForADreading = 100 * 1000; // 100mS
  uint64_t TimePastPublish = esp_timer_get_time(); // used by publish
  uint64_t TimeADreading   = esp_timer_get_time();
  TickType_t xLastWakeTime = xTaskGetTickCount();
  const TickType_t xFrequency = 10; //delay for 10mS
  float    RemainingMoisture = 100.0f; //prevents pump turn on during start up
  for (;;)
  {
    //read AD values every 100mS.
    if ( (esp_timer_get_time() - TimeADreading) >= TimeForADreading )
    {
      xEventGroupSetBits( eg, evtADCreading );
      TimeADreading = esp_timer_get_time();
    }
    xQueueReceive(xQ_RM, &RemainingMoisture, 0 ); //receive queue stuff no waiting
    //read gpio 0 is water level good. Yes: OK to run pump : no pump off.   remaining moisture good, denergize water pump otherwise energize water pump.
    if ( gpio_get_level( GPIO_NUM_0 ) )
    {
      if ( RemainingMoisture >= 40.0f ) {
        WaterPump0_off();
      }
      if ( RemainingMoisture <= 20.0f )
      {
        WaterPump0_on();
      }
      //xSemaphoreGive( sema_RemainingMoisture );
    } else {
      log_i( "water level bad " );
      WaterPump0_off();
    }
    // publish to MQTT every 5000000uS
    if ( (esp_timer_get_time() - TimePastPublish) >= TimeToPublish )
    {
      xQueueOverwrite( xQ_RemainingMoistureMQTT, (void *) &RemainingMoisture );// data for mqtt publish
      TimePastPublish = esp_timer_get_time(); // get next publish time
    }
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
  }
  vTaskDelete( NULL );
}// end fDoMoistureDetector()

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