Нужна помощь с анализом погодных предупреждений NWS JSON, вызывающих сброс на ESP8266.

Я пытаюсь проанализировать строку JSON из оповещений Национальной метеорологической службы и столкнулся с проблемой: код не может проанализировать значение, и устройство автоматически сбрасывается. Раньше я использовал этот код в другом API, чтобы получить текущие погодные условия, и это работает нормально. Я не уверен, что делаю неправильно, и буду очень признателен за любой совет или помощь. Спасибо!

Вот ошибка:

21:13:07.521 -> сброс wdt
21:13:07.521 -> загрузка 0x4010f000, len 3424, комната 16
21:13:07.521 -> хвост 0
21:13:07.521 -> контрольная сумма 0x2e
21:13:07.521 -> загрузка 0x3fff20b8, len 40, комната 8
21:13:07.521 -> хвост 0
21:13:07.521 -> контрольная сумма 0x2b
21:13:07.521 -> csum 0x2b
21:13:07.521 -> v00045d00
21:13:07.521 -> ~ld
21:13:07.555 -> ����n�r��n|�l�l`b��|r�l�n��n�l`��r�l�l��
_

И вот мой код:

#include <ESP8266WiFi.h>
#include <ArduinoJson.h>

const char* ssid     = "mySSID";                      // SSID локальной сети
const char* password = "myPassword";                 // Пароль в сети

WiFiClient client;
char weatherServerName[] = "api.weather.gov";
String result;

//Для тестирования измените эту зону на любую зону NWS, в которой в настоящее время наблюдается предупреждение о погоде
//Найдите активную зону оповещения, перейдя на https://api.weather.gov/alerts/active и найдя код в поле "affectedZones"
String zone = "LEZ144";                            


bool hasAlert = false;

void setup() { 
  Serial.begin(115200);  
  Serial.println("=====================================================================================================");   
  Serial.println("Connecting");

  WiFi.begin(ssid, password);
  
            while (WiFi.status() != WL_CONNECTED) 
            {
            delay(500);            
            Serial.print(".");            
            }
    
  Serial.println("Connected");
  delay(1000);
}

void loop() {
  Serial.println(":D");
  getWeatherAlerts();
  delay(100000);
}

void getWeatherAlerts()
{
  String server = weatherServerName;

  if (client.connect(server, 443))     
       {                                        
          client.println("GET /alerts/active?zone=" + zone);
          client.println("User-Agent: ArduinoWiFi/1.1");
          client.println("Connection: close");
          client.println();
          } 
  else {
         Serial.println("connection failed");        //сообщение об ошибке, если клиент не подключается
         Serial.println();
       }

                                       //ждём данных
  while (client.connected() || client.available())    
       {                                             //подключено или данные доступны
         char c = client.read();                     // получает байт из буфера Ethernet
         result = result+c;
       }

  client.stop();                                      //остановим клиент
  result.replace('[', ' ');
  result.replace(']', ' ');
  Serial.println(result);
  char jsonArray [result.length()+1];
  result.toCharArray(jsonArray,sizeof(jsonArray));
  jsonArray[result.length() + 1] = '\0';
  StaticJsonDocument<8196> root;
  DeserializationError error = deserializeJson(root, jsonArray);

  if (error)
    {      
      Serial.println("parseObject() failed");
    }


  String features = root["features"];
  
  Serial.println(features);

  if(features.length() == 0)
  {
    Serial.println(features);
    hasAlert = false;
  }  
  else
  {
    String severity = root["features"]["severity"];  
    Serial.println(severity);
    if(severity == "Moderate" || severity == "Severe")
    {
      hasAlert = true;      
    }
    else
    {
      hasAlert = false;
    }
  }

  Serial.println(hasAlert);
}

, 👍1

Обсуждение

распечатайте полученное, прежде чем пытаться его изменить, @jsotola


2 ответа


Лучший ответ:

6

По умолчанию размер стека ограничен 4 КБ на ESP8266, поэтому вы не можете хранить там документ размером 8 КБ.

Чтобы устранить эту проблему, замените StaticJsonDocument на DynamicJsonDocument, чтобы переместить буфер в кучу.

См. также: Почему мое устройство выходит из строя или перезагружается?

,

2

В первой строке сообщения об ошибке содержится хорошая подсказка:

21:13:07.521 -> wdt reset

Сторожевой таймер ESP-8266 (WDT) перезагрузит устройство, если оно не было правильно «запитано» в течение определенного периода времени (тайм-аут сторожевого таймера).

Как заметил @Juraj, библиотеки ESP-8266 Arduino «полезно» добавляют каналы WDT в различные моменты, предполагая, что тайм-аут связан с тем, что ваш код либо дает сбой (переполнение в недопустимый программный код), либо истекает время ожидания (действительный код, но застрял в петле).

Информацию обратной трассировки, напечатанную при сбросе, можно использовать для определения места возникновения WDT конкретно в вашем коде, чтобы вы могли найти проблему (которая может быть той, которую заметил @Benoit Blanchon). Я обнаружил, что этот декодер исключений очень полезен для преобразования кода в функции вашего кода.

Также стоит отметить, что «искаженные символы» после информации обратной трассировки сброса WDT — это сообщение о запуске загрузчика, скорость которого фиксирована на 74880 бод. Вы можете изменить скорость передачи данных последовательного терминала, чтобы увидеть их (и «искажать» другие сообщения).

(Информация о сторожевых таймерах и кормлении ниже не имеет прямого отношения к данному случаю, как заметил @Juraj, но оставлена для контекста)

Это пример документа от TI, в котором представлены сторожевые таймеры. Для ESP8266 вы можете найти этот документ techtutorialsx более полезным. Таким образом, вам нужно либо отключить сторожевой таймер, либо периодически выдавать

ESP.wdtFeed();

команды. Отключение сторожевого таймера — это на первый взгляд простой вариант, но он отключает действительно полезный инструмент, который поможет вам более изящно обрабатывать непредвиденные условия/ошибки в вашем проекте/продукте, поэтому я бы посоветовал вам научиться его использовать, а затем накормите его, как указано выше.

(Как заметил @Benoit Blanchon, есть и другие проблемы реализации, которые следует решить и, возможно, заслуживают отдельного поста при проверке кода. Однако я хотел объяснить причину сброса, о котором вы спрашивали, а это не так. Это связано исключительно с JSON и будет продолжать происходить, если вы не предпримете действия, описанные выше)

,

здесь wdt не подается после сбоя, @Juraj

@Juraj, wdt вообще не подается, что приводит к сбросу wdt., @rolinger

на esp8266 подача wdt происходит автоматически, если цикл() заканчивается, с задержками, во многих вызовах функций, @Juraj

Спасибо @Juraj, обновлено соответственно., @rolinger

поэтому «размер стека на ESP8266 ограничен 4 КБ, поэтому вы не можете хранить там документ размером 8 КБ». для меня это хорошее объяснение аварии. «сброс wdt» — это просто отвлечение. Бенуа Бланшон — автор библиотеки ArduinoJson., @Juraj