Search code examples
arduinoesp8266

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


I got an MPU connected to a wemos d1 mini. The sensor send 3 values: X,Y and Z axis. Since my project is solar powered I need to reduce power consumption. In order to do so I want to read the 3 values of the MPU every 3 seconds, store the values in an array and after 5 minutes of sampling power up the wifi and send the array via mqtt to my topic.

I've already tested every part of my code and everything works. For example if I try to send an array of three objects it works perfectly But when I try to send an array of 100 objects it doesn't work.

(Note: Where the above "100" come from? If I need to send data every 5 minutes and I read values every 3 seconds here I have 100 samplings)

Hope someone could help

unsigned long t_start;

void setup()
{
    t_start = millis();
}
//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>();

    if (millis() - t_start >= 3000) {
        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;
        }

        t_start = millis();
    }
}

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

Solution

  • If you want one measure every three seconds instead of 100 measures every 3 seconds, the code should look like this:

    #define MQTT_KEEPALIVE 300
    // headers ...
    // setup() ...
    
    void loop() {
      //Create an empty array
      JsonArray arr = doc.to<JsonArray>();
    
      static auto t_start = millis(); // static will preserve last value even after exiting loop
    
      int8_t count = 0;
      while (count < 100) { // stays here whole 300s, so if the keep alives are needed or doing something else, it should be inside too
        client.loop(); // sugested in comments
    
        if (millis() - t_start >= 3000) {
          t_start += 3000;
          ++count;
    
          //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;
        }
    
        // handling keep alives every X seconds as it's unlikely as long as 300s:
        // if (...) sendKeepAlive();
      }
      
      // after 100 measures it'll get here:
    
      //MQTT PUBLISHING JSON PACKAGE
      char mqttData[MQTT_BUFFER];
      serializeJson(doc, mqttData);
      Serial.println(mqttData);
      int ret = client.publish("esp8266/JSON", mqttData);
    } //end of loop
    

    However it should solve just most obvious issue with the code only. There might be others, like buffers might be too small, or so...

    And it's untested, I don't have this HW setup