esp8266 通过 MQTT 发送大 JSON 文档时出现问题

Problem with esp8266 sending large JSON Document via MQTT

我开发了一个从传感器读取数据的小应用程序,将它们存储在我的 wemos D1 mini (esp8266) 的 SPIFFS 内存中,然后创建一个 JSON 文档并通过 MQTT 将其发送到我的主题。问题是,只要我发送一个包含 10 个对象的 JSON 文档,一切都很好,但是当我将文档的大小增加到超过 10 个对象时,就没有任何效果。最后我需要发送一个 JSON 文档,里面有 100 个对象。

我已经做了什么?

  1. 我正在使用 PubSubClient 并且我已经将 MAX_PACKET_SIZE 设置为正确的值

  2. 使用 arduinojson 助手我发现了我的 JSON 文档的大小(8192 字节)

  3. 我尝试使用mqtt.fx测试问题是esp8266还是mqtt broker。使用 mqtt.fx 我可以发送包含 100 个对象的 JSON 文档

  4. 一旦我增加 JSON 文档的大小,我的 arduino IDE.

    的串行监视器就会收到 wdt 错误

  5. 我在互联网上搜索 wdt 错误,但我不明白它们是什么以及如何解决我的问题

  6. 最后我已经尝试在串行监视器上显示 file.txt 在我存储数据的 SPIFFS 中,我可以存储然后读取 100 个对象

所以最后我认为这是一个 esp8266 问题,而不是 PubSubClient 或 MQTT。我对吗? 你们这里有没有人以前遇到过这个问题或者我可以做一些其他测试运行?

I search the internet for wdt error but I don't get what they are and how to solve my problem

WDT 代表看门狗定时器。 https://os.mbed.com/cookbook/WatchDog-Timer#:~:text=A%20watchdog%20timer%20(WDT)%20is,a%20software%20or%20hardware%20fault.

A watchdog timer (WDT) is a hardware timer that automatically generates a system reset if the main program neglects to periodically service it. It is often used to automatically reset an embedded device that hangs because of a software or hardware fault. Some systems may also refer to it as a computer operating properly (COP) timer. Many microcontrollers including the mbed processor have watchdog timer hardware.

让我们用一个例子来描绘一幅更好的图画。假设您设置了一个 10 秒时间的 WDT。然后 WDT 从 10 秒开始倒计时。如果它达到 0,处理器将重置。 “喂养”WDT 会将倒计时重置为原始值,在这种情况下为 10 秒。因此,如果 WDT 已经倒计时到还剩 4 秒并且您给它喂食,它会将倒计时重置回 10 并再次开始倒计时。

Does anyone of you here ever encountered this problem before or have some other test I can run?

在我看来,发送一个更大的 JSON 对象需要比 WDT 设置的时间更长的时间。一种可能是将 JSON 对象分解成多个部分,然后以较小的块而不是一个大块的形式发送。这样 WDT“喂食”之间的时间就减少了。我不知道你是否可以改变这一点。但这至少应该让您更好地了解正在发生的事情。

好吧,最后问题是发送一个大的 JsonDocument 触发了 WDT,我发现解决这个问题的唯一方法是,正如 所建议的那样,创建一个包含所有 100对象,然后调用函数将该文件拆分为 10 个较小的文件,并通过 HTTP 请求或 Mosquitto 通过 Internet 发送每个文件。

假设你已经在spiffs内存中创建了主文件,那么:

分割主文件:

void WritePacks() {
  
  sourceFile = LittleFS.open("/file.txt", "r");
  if (!sourceFile) {
    Serial.println(F("Error: file.txt open failed"));
  } else {
    Serial.println("File open w/ success");
    for (byte idx = 0; idx < outputCount; idx++) {
      String aLine;
      aLine.reserve(capacity);
      if (sourceFile.available() == 0) break;
      destinationFile = LittleFS.open(outputFileNames[idx], "w");
      if (!destinationFile) {
        Serial.print(F("can't open destination "));
        Serial.println(outputFileNames[idx]);
        break;
      } else {
        int lineCount = 0;
        while (sourceFile.available() && (lineCount <= 10)) {
          aLine = sourceFile.readStringUntil('\n');
          destinationFile.println(aLine); // double check if the '\n' is in the String or not (--> print or println accordingly)
          lineCount++;
        }
        outputIndex = idx;
        Serial.println(outputIndex);
        destinationFile.close();
      }
    } // end for
    sourceFile.close();
  }
}//end WritePacks

此发布:

//------ HTTP Publish ------
void httpPublish(){

  const char * outputFileNames[] = {"/out1.txt", "/out2.txt", "/out3.txt", "/out4.txt", "/out5.txt", "/out6.txt", "/out7.txt", "/out8.txt", "/out9.txt", "/out10.txt"};
  const byte outputCount = sizeof outputFileNames / sizeof outputFileNames[0];
  byte outputIndex = 0;
  
  File sourceFile;
  File destinationFile;
  
  //Serial.println(capacity);
  

  for (byte idx = 0; idx < outputCount; idx++) {

      DynamicJsonDocument doc(capacity);
      DynamicJsonDocument globalDoc(capacity);
      StaticJsonDocument <1024> localDoc;
      String aLine;
      aLine.reserve(capacity);
      
      destinationFile = LittleFS.open(outputFileNames[idx], "r");
      if (!destinationFile) {
        Serial.print(F("can't open destination "));
        Serial.println(outputFileNames[idx]);
        break;
      } else {
        Serial.print("Reading: ");
        Serial.println(outputFileNames[idx]);
        //int lineCount = 0;
        while (destinationFile.available()) {
          aLine = destinationFile.readStringUntil('\n');
          DeserializationError error = deserializeJson(localDoc, aLine);
          if (!error) globalDoc.add(localDoc);  
          else{ Serial.println("Error Writing All files");}
        }//while

        JsonObject Info = doc.createNestedObject("Info");
        Info["Battery"] = battery;
        Info["ID"] = id;
        Info["Latitudine"] = latitudine;
        Info["Longitudine"] = longitudine;
    
        
        JsonArray Data = doc.createNestedArray("Data"); 
        Data.add(globalDoc);
    
        HTTPClient http;
        //Send request
        http.begin("yourURL");
        char buffer[capacity];
        size_t n = serializeJson(doc, buffer);
        
        http.POST(buffer);
        Serial.println(buffer);
        http.end();
        destinationFile.close();
      }
    }// end for   
}//end httpPublish