首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >更新:内存泄漏与WiFiClientSecure (电报)和WiFiClient (MQTT)

更新:内存泄漏与WiFiClientSecure (电报)和WiFiClient (MQTT)
EN

Stack Overflow用户
提问于 2020-08-13 13:24:54
回答 1查看 728关注 0票数 0

这个标题很容易解释,就像我在Exception 28 thrown on ESP8266-01 when connected to Adafruit MQTT and Telegram上发布的另一个问题一样

有人可能会说这是同样的问题,但实际上这是它的后续,我认为这是一个独立的问题,因为它也可能帮助其他人,而且在其他互联网上也没有真正涉及到。我还将发布我的全部代码(就像我在前一个问题上所做的那样),尽管StackOverflow建议只发布最小值来复制错误,因为我觉得完全复制错误是需要的。(私有数据改为私有数据)

代码语言:javascript
复制
#include "UniversalTelegramBot.h"
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <Adafruit_MQTT.h>
#include <Adafruit_MQTT_Client.h>

#define BOTtoken "PRIVATE"
#define fanPin 2
#define myChatId "PRIVATE"
#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  1883
#define AIO_USERNAME  "PRIVATE"
#define AIO_KEY  "PRIVATE"

char ssid[] = "PRIVATE";
char password[] = "PRIVATE";
bool fanState;
unsigned long lastTimeBotRan = 0;
unsigned long checkTime = 1000;
int numNewMessages;
unsigned long timerStartPoint = 0;
bool timerStart;
String chat_id;
String text;
int messagesNumber;
String timerString;
String  Request;
const unsigned long rst = 300000;
boolean MQTT_connect();


WiFiClientSecure telegramClient;
WiFiClient MQTTClient;
UniversalTelegramBot bot(BOTtoken, telegramClient);
Adafruit_MQTT_Client mqtt(&MQTTClient, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
Adafruit_MQTT_Subscribe PRIVATE = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/PRIVATE");

void checkUpdates(int numNewMessages) {
  for (int i = 0; i < numNewMessages; i++) {
    chat_id = String(bot.messages[i].chat_id);
    text = bot.messages[i].text;
    String from_name = bot.messages[i].from_name;

    if (chat_id != myChatId) {
      bot.sendMessage(chat_id, "Unauthorized user, please refrain from texting this bot again.", "");
      continue;
    }

    if (text == "/start") {
      bot.sendMessage(chat_id, "Welcome " + from_name + "!\n"
                              "Control your fan remotely!\n\n"
                              "/fanon: switch the fan ON\n"
                              "/fanoff: switch the fan OFF\n"
                              "/state: get the current state of the fan"
                              "/timer15: run fan for 15 minutes"
                              "/timer30: run fan for 30 minutes"
                              "/timer60: run fan for 1 hour"
                              "/timer: run fan for the amount of time you specify", "Markdown");
    }

    if (text == "/fanon") {
      digitalWrite(fanPin, HIGH);
      Serial.println("Fan on");
      fanState = true;
      bot.sendMessage(chat_id, "Your fan is ON", "");
    }

    if (text == "/fanoff") {
      fanState = false;
      timerStart = false;
      digitalWrite(fanPin, LOW);
      Serial.println("Fan off");
      bot.sendMessage(chat_id, "Your fan is OFF", "");
    }

    if (text == "/state") {
      if (digitalRead(2) == HIGH) {
        bot.sendMessage(chat_id, "Your fan is ON", "");
      } else {
        bot.sendMessage(chat_id, "Your fan is OFF", "");
      }
    }

    if (text == "/timer15") {
      timerStartPoint = millis();
      digitalWrite(fanPin, HIGH);
      timerStart = true;
      Serial.print("(/timer15) Fan on at ");
      Serial.println(timerStartPoint);
      bot.sendMessage(chat_id, "Your fan will run for 15 minutes", "");
      launchTimer(15);
    }

    if (text == "/timer30") {
      digitalWrite(fanPin, HIGH);
      timerStart = true;
      timerStartPoint = millis();
      Serial.print("(/timer30) Fan on at ");
      Serial.println(timerStartPoint);
      bot.sendMessage(chat_id, "Your fan will run for 30 minutes", "");
      launchTimer(30);
    }

    if (text == "/timer60") {
      digitalWrite(fanPin, HIGH);
      timerStart = true;
      timerStartPoint = millis();
      Serial.print("(/timer60) Fan on at ");
      Serial.println(timerStartPoint);
      bot.sendMessage(chat_id, "Your fan will run for 1 hour", "");
      launchTimer(60);
    }

    if (text == "/timer") {
      messagesNumber = bot.last_message_received + 1;
      bot.sendMessage(chat_id, "How long do you want the fan to run for? (in minutes)", "");
      Serial.println(messagesNumber);

      while (messagesNumber == (bot.last_message_received + 1)) {
        checkUpdates(bot.getUpdates(bot.last_message_received + 1));
        timerString = bot.messages[i].text;
        yield();
      }

      if (messagesNumber < (bot.last_message_received + 1)) {
        unsigned long timer = timerString.toInt();
        Serial.println(timer);
        digitalWrite(fanPin, HIGH);
        timerStart = true;
        timerStartPoint = millis();
        Serial.print("(/timer) Fan on at ");
        Serial.println(timerStartPoint);
        bot.sendMessage(chat_id, "Your fan will run for " + timerString + " minutes", "");
        launchTimer(timer);
      }
    }
    text = "";
  }
}

void launchTimer(unsigned long timeInMinutes) {
  unsigned long timeInMillis = timeInMinutes * 60 * 1000;

  while (timerStart) {
    checkUpdates(bot.getUpdates(bot.last_message_received + 1));
    if (MQTT_connect()) {
      Adafruit_MQTT_Subscribe *subscription_name;
      while ((subscription_name = mqtt.readSubscription(4000))) {
        if (subscription_name == &PRIVATE) {
          Request = ((char *)PRIVATE.lastread);
          if (Request == "fanon") {
            digitalWrite(fanPin, HIGH);
            Serial.println("(Control panel) Fan on");
            fanState = true;
            bot.sendMessage(myChatId, "Fan turned on through Control Panel", "");
          }
          if (Request == "fanoff") {
            fanState = false;
            timerStart = false;
            Serial.println("(Control panel) Fan off");
            digitalWrite(fanPin, LOW);
            bot.sendMessage(myChatId, "Fan turned off through Control Panel", "");
          }
          if (Request == "timer15") {
            timerStartPoint = millis();
            digitalWrite(fanPin, HIGH);
            timerStart = true;
            Serial.print("(CP /timer15) Fan on at ");
            Serial.println(timerStartPoint);
            bot.sendMessage(myChatId, "Fan turned on for 15 minutes through Control Panel", "");
            launchTimer(15);
          }
          if (Request == "timer30") {
            digitalWrite(fanPin, HIGH);
            timerStart = true;
            timerStartPoint = millis();
            Serial.print("(CP /timer30) Fan on at ");
            Serial.println(timerStartPoint);
            bot.sendMessage(myChatId, "Fan turned on for 30 minutes through Control Panel", "");
            launchTimer(30);
          }
          if (Request == "timer60") {
            digitalWrite(fanPin, HIGH);
            timerStart = true;
            timerStartPoint = millis();
            Serial.print("(CP /timer60) Fan on at ");
            Serial.println(timerStartPoint);
            bot.sendMessage(myChatId, "Fan turned on for 1 hour through Control Panel", "");
            launchTimer(60);
          }
        }
      }
    }
    if (millis() - timerStartPoint > timeInMillis) {
      digitalWrite(fanPin, LOW);
      timerStart = false;
      Serial.print("Timer run out at ");
      Serial.println(millis());
      bot.sendMessage(myChatId, "Fan turned off because timer ran out", "");
    }
    yield();
  }
}

boolean MQTT_connect() {
  int8_t ret;
  if (mqtt.connected()) {
    return true;
  }  uint8_t retries = 3;
  while ((ret = mqtt.connect()) != 0) {
    mqtt.disconnect();
    delay(2000);
    retries--;
    if (retries == 0) {
      return false;
    }
  } return true;
}


void setup() {
  Serial.begin(115200);
  telegramClient.setInsecure();

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);

  Serial.print("Connecting Wifi: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

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

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  pinMode(fanPin, OUTPUT);
  delay(10);
  digitalWrite(fanPin, LOW);


  Request = "";
  mqtt.subscribe(&PRIVATE);

  if (MQTT_connect()) {
    Serial.println("mqtt connected");
  }
  else {
    Serial.println("mqtt connection failed");
  }

}

void loop() {
  if (millis() - lastTimeBotRan > checkTime) {
    numNewMessages = bot.getUpdates(bot.last_message_received + 1);

    while (numNewMessages) {
      checkUpdates(numNewMessages);
      numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    }
    lastTimeBotRan = millis();
  }

  delay(1000);

  if (MQTT_connect()) {
    Adafruit_MQTT_Subscribe *subscription_name;
    while ((subscription_name = mqtt.readSubscription(4000))) {
      if (subscription_name == &PRIVATE) {
        Request = ((char *)PRIVATE.lastread);
        if (Request == "fanon") {
          digitalWrite(fanPin, HIGH);
          Serial.println("(Control panel) Fan on");
          fanState = true;
          bot.sendMessage(myChatId, "Fan turned on through Control Panel", "");
        }
        if (Request == "fanoff") {
          fanState = false;
          timerStart = false;
          Serial.println("(Control panel) Fan off");
          digitalWrite(fanPin, LOW);
          bot.sendMessage(myChatId, "Fan turned off through Control Panel", "");
        }
        if (Request == "timer15") {
          timerStartPoint = millis();
          digitalWrite(fanPin, HIGH);
          timerStart = true;
          Serial.print("(CP /timer15) Fan on at ");
          Serial.println(timerStartPoint);
          bot.sendMessage(myChatId, "Fan turned on for 15 minutes through Control Panel", "");
          launchTimer(15);
        }
        if (Request == "timer30") {
          digitalWrite(fanPin, HIGH);
          timerStart = true;
          timerStartPoint = millis();
          Serial.print("(CP /timer30) Fan on at ");
          Serial.println(timerStartPoint);
          bot.sendMessage(myChatId, "Fan turned on for 30 minutes through Control Panel", "");
          launchTimer(30);
        }
        if (Request == "timer60") {
          digitalWrite(fanPin, HIGH);
          timerStart = true;
          timerStartPoint = millis();
          Serial.print("(CP /timer60) Fan on at ");
          Serial.println(timerStartPoint);
          bot.sendMessage(myChatId, "Fan turned on for 1 hour through Control Panel", "");
          launchTimer(60);
        }
      }
    }
  }

  if (!mqtt.ping()) {
    mqtt.disconnect();
  }
}

现在,问题是:我想实例化WiFiClient (连接到Adafruit )和WiFiClientSecure (连接到我的Telegram bot),而不以崩溃告终,然后是一个异常28堆栈跟踪(我已经在链接的另一个问题中发布了一个“正常”和解码版本)。我知道,经过几个小时的研究,我无法实例化WiFiClientSecure的两个实例,因为它将超过ESP01上可用的堆,而且我还知道,仅WiFiClient或仅WiFiClientSecure就不会碰巧抛出所述异常。

我没有发现WiFiClient和WiFiClientSecure不能一起使用,但是我可能遗漏了什么。因此,我的问题是:是否可以在相同的代码中同时使用WiFiClient和WiFiClientSecure,用于两个不同的目的(分别是MQTT和WiFiClientSecure)?

我期待着阅读任何一条建议,因为我目前对想法无所适从。提前感谢每一个愿意帮忙的人。

编辑:对于任何感兴趣的人,以下是我的最新发现:

  • 将ESP01的CPU从80 MHz提高到160 MHz,这有助于减轻崩溃的影响,实际上它在8小时内只崩溃了一次。从每30分钟到8小时的崩溃,肯定是向前迈进了一步;
  • (感谢romkey的建议)发现,WiFiClient和WiFiClientSecure并不是不兼容的,问题是由自由堆造成的。通过删除String并将其转换为char数组,释放堆,使程序不会在整个13个小时内崩溃。我可能会进一步测试它,让它持续超过24小时,看看它是否真的解决了。以防万一,我将更新.

更新:发现问题并更改标题。问题完全在于这两个库的堆使用。这两个库都使用大量的堆空间,过一段时间就会耗尽,导致异常28,因为,据我所知,ESP试图从其内存的错误部分读取,导致它崩溃。我将在3分钟内附加堆的串行输出:

代码语言:javascript
复制
41552
19448
20008
20120
20312
20200
20120
20120
20120
20312
20120
20120
20120
20312
20312
20312
20312
20312
20312
20504
20312
20312
19640

如您所见,第一个实例的堆显示超过40k,这是正常的,因为51kish是最大值。然后它跳到20000,然后就用完了,尽管ESP在几分钟后恢复了它自己的内存。

EN

回答 1

Stack Overflow用户

发布于 2021-01-07 10:54:00

在我的WiFiClient多传感器检查和发布项目中,我也使用了WiFiClientSecure和ESP8266。虽然我的WifiClient一直在运行(对于MQTT和ThingSpeak),但我决定将安全连接(为了更少地发布到GoogleSheets --每30分钟一次)进行连接。整个项目代码太大(有5570行),下面是其中的一部分,其中有一些注释介绍了堆的使用情况:

代码语言:javascript
复制
// heap size before call of the function: 37112
int SendGSCRPT() {
  showHeap();   // 35312
  WiFiClientSecure GoogleClient;
  showHeap();   // 27512
  GoogleClient.setInsecure();
  if (!GoogleClient.connect("script.google.com", 443)) {
    GoogleClient.stop();
    return 0;
  }
  showHeap();  // 9840 !!!
  char sGog[200];
  snprintf(sGog, sizeof(sGog), "GET %s HTTP/1.1\r\nHost: script.google.com\r\nUser-Agent: PRIVATE\r\nConnection: close\r\n\r\n", "PRIVATE");
  GoogleClient.print(sGog);
  Serial.println("request sent!");
  int res = 1;
  GoogleClient.stop();
  showHeap(); // 30104
  return res;
}
// heap size after function releases all the memory taken: 37112 again !!!
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63396210

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档