esp8266, почему теряются последние значения из буфера?
- Войдите на сайт для отправки комментариев
Пнд, 12/08/2019 - 16:00
полгода работало и перестало...
#include <ESP8266WiFi.h> // Библиотека для создания Wi-Fi подключения (клиент или точка доступа) #include <WiFiClient.h> // Библиотека для связи с сетевыми хостами (локальными и интернет) #include <TimeLib.h> // Библиотека для работы с временем #include <ArduinoJson.h> // Библиотека для разбора JSON const char* ssid = "Lenovo"; // Указываем имя WiFi-сети, к которой будет подключаться ESP8266 для доступа в Интернет const char* password = "88888"; // Указываем пароль для подключения к WiFi-сети String regionID = "11207"; // Код региона по Yandex для выбора часового пояса https://tech.yandex.ru/xml/doc/dg/reference/regions-docpage/ String SunriseTime, SunsetTime, Temperature; char icon[20]; WiFiClient client; // Создаём объект для работы с удалёнными хостами void setup() { Serial.begin(115200); // Инициализируем вывод данных на серийный порт со скоростью 9600 бод Serial.println("\n\n"); WiFi.begin(ssid, password); // Соединяемся с WiFi-сетью while (WiFi.status() != WL_CONNECTED) // Пока соединение не установено delay(500); // делаем задержку в пол секунды, пока соединение не установится while (!TimeAndWeather()) // Синхронизируем время микроконтроллера с реальным временем и получаем информацию о погоде delay(500); Serial.print("Tekuschie data i vremya: "); digitalClockDisplay(); // Выводим дату и время Serial.println(); Serial.println("Voshod v " + SunriseTime); // Выводим время восхода Serial.println("Zakat v " + SunsetTime); // Выводим время восхода Serial.println(); Serial.println("Temperatura: " + Temperature + " C"); // Выводим время восхода WeatherDisplay(); // Выводим информацию о погоде } void loop() {} bool TimeAndWeather () { // Функция синхронизации времени работы программы с реальным временем и получения информации о погоде if (client.connect("yandex.com",443)) { // Если удаётся установить соединение с указанным хостом (Порт 443 для https) client.println("GET /time/sync.json?geo=" + regionID + " HTTP/1.1\r\nHost: yandex.com\r\nConnection: close\r\n\r\n"); // Отправляем параметры запроса delay(300); // Даём серверу время, чтобы обработать запрос char endOfHeaders[] = "\r\n\r\n"; // Системные заголовки ответа сервера отделяются от остального содержимого двойным переводом строки if (!client.find(endOfHeaders)) { // Отбрасываем системные заголовки ответа сервера Serial.println("Invalid response"); // Если ответ сервера не содержит системных заголовков, значит что-то пошло не так return false; // и пора прекращать всё это дело } Serial.println("chitaem dannie"); String line2; while ( client.available() ) { char c = client.read(); line2 += c; } Serial.print("line2= "); Serial.println(line2); //line2=line2+"}]}}}"; // const size_t capacity = 750; // Эта константа определяет размер буфера под содержимое JSON (https://arduinojson.org/v5/assistant/) // DynamicJsonBuffer jsonBuffer(capacity); // Инициализируем буфер под JSON DynamicJsonDocument root(2048); // JsonObject& root = jsonBuffer.parseObject(client); // Парсим JSON-модержимое ответа сервера // Parse JSON object DeserializationError error = deserializeJson(root, line2); if (error) { Serial.print(F("deserializeJson() failed: ")); Serial.println(error.c_str()); return 0; } client.stop(); // Разрываем соединение с сервером String StringCurrentTime = line2.substring(8,18); // String StringCurrentTime = root["time"].as<String>().substring(0,10); // Достаём значение реального текущего времени из JSON и отбрасываем от него миллисекунды String StringOffset = root["clocks"][regionID]["offset"].as<String>(); // Достаём значение смещения времени по часовому поясу (в миллисекундах) SunriseTime = root["clocks"][regionID]["sunrise"].as<String>(); // Достаём время восхода - Третий уровень вложенности пары ключ/значение clocks -> значение RegionID -> sunrise SunsetTime = root["clocks"][regionID]["sunset"].as<String>(); // Достаём время заката - Третий уровень вложенности пары ключ/значение clocks -> значение RegionID -> sunset Temperature = root["clocks"][regionID]["weather"]["temp"].as<String>();// Достаём время заката - Четвёртый уровень вложенности пары ключ/значение clocks -> значение RegionID -> weather -> temp strcpy(icon, root["clocks"][regionID]["weather"]["icon"].as<String>().c_str()); // Достаём иконку - Четвёртый уровень вложенности пары ключ/значение clocks -> значение RegionID -> weather -> icon // jsonBuffer.clear(); // Очищаем буфер парсера JSON unsigned long CurrentTime = StringToULong(StringCurrentTime); // Переводим значение реального времени в секундах, считанное с Яндекса, из String в unsigned long unsigned long Offset = StringToULong(StringOffset) / 1000; // Переводим значение смещения времени по часовому поясу, считанное с Яндекса, из String в unsigned long и переводим его в секунды setTime(CurrentTime + Offset); // Синхронизируем время return true; } } unsigned long StringToULong(String Str) { // Эта функция преобразует String в unsigned long unsigned long ULong = 0; for (int i = 0; i < Str.length(); i++) { // В цикле посимвольно переводим строку в unsigned long char c = Str.charAt(i); if (c < '0' || c > '9') break; ULong *= 10; ULong += (c - '0'); } return ULong; } void digitalClockDisplay(){ // Эта функция выводит дату и время на монитор серийного порта Serial.print(leadNull(day())); Serial.print("."); Serial.print(leadNull(month())); Serial.print("."); Serial.print(year()); Serial.print(" "); Serial.print(leadNull(hour())); Serial.print(":"); Serial.print(leadNull(minute())); Serial.print(":"); Serial.print(leadNull(second())); Serial.println(); } String leadNull(int digits){ // Функция добавляет ведущий ноль String out = ""; if(digits < 10) out += "0"; return out + String(digits); } void WeatherDisplay(){ char * out = strtok(icon,"-"); // Выделяем первую часть из строки до символа '-' while (out != NULL) { // Выделяем последующие части строки в цикле, пока значение out не станет нулевым (пустым) if (String(out) == "skc") // Перебираем в условиях все возможные варианты, зашифрованные в названии иконки Serial.println("Yasno"); else if (String(out) == "ovc") Serial.println("Pasmurno"); else if (String(out) == "bkn") Serial.println("Oblachno"); else if (String(out) == "ra") Serial.println("Dozhd'"); else if (String(out) == "ts") Serial.println("Groza"); else if (String(out) == "sn") Serial.println("Sneg"); else if (String(out) == "bl") Serial.println("Metel'"); else if (String(out) == "fg") Serial.println("Tuman"); else if (String(out) == "n") Serial.println("\nTemnoe vremya sutok"); else if (String(out) == "d") Serial.println("\nSvetloe vremya sutok"); out = strtok(NULL,"-"); // Выделяем очередную часть } }
обрезает последние пять скобок
chitaem dannie
line2= {"time":1565610960269,"clocks":{"11207":{"id":11207,"name":"Kopeysk","offset":18000000,"offsetString":"UTC+5:00","showSunriseSunset":true,"sunrise":"05:20","sunset":"20:35","isNight":false,"skyColor":"#71c0f4","weather":{"temp":25,"icon":"bkn-d","link":"https://yandex.ru/pogoda/kopeysk"},"parents":[{"id":11225,"name":"Chelyabinsk Oblast"},{"id":225,"name":"Russia"
deserializeJson() failed: IncompleteInput
если раскоментировать 62 сточку то
chitaem dannie
line2= {"time":1565609452719,"clocks":{"11207":{"id":11207,"name":"Kopeysk","offset":18000000,"offsetString":"UTC+5:00","showSunriseSunset":true,"sunrise":"05:20","sunset":"20:35","isNight":false,"skyColor":"#6ec0f5","weather":{"temp":24,"icon":"bkn-d","link":"https://yandex.ru/pogoda/kopeysk"},"parents":[{"id":11225,"name":"Chelyabinsk Oblast"},{"id":225,"name":"Russia"
Tekuschie data i vremya: 12.08.2019 16:30:52
Voshod v 05:20
Zakat v 20:35
Temperatura: 24 C
Oblachno
Svetloe vremya sutok
похоже что слищком рано заканчиваете читать. У вас код написан из предположения, что весь json придет одной посылкой - а это в общем-то, никто не гарантирует. Рано или поздно этот код должен был заглючить - и вот заглючил.
Читайте входной поток, пока не получите все закрывающие скобки.
и где об этом можно почитать? или пример глянуть?
и где об этом можно почитать? или пример глянуть?
честно говоря, не знаю. Могу только на словах
Заведите счетчик скобок.
Когда Вы в строчке 56 читаете символ - нужно проверить, не является ли он скобкой. Сначала читаете ответ до первой открывающей скобки - тут начинается json Потом, если скобка открывающая - увеличиваете счетчик, закрывающая - уменьшаете. Когда счетчик снова придет к нулю - значит весь json прочитан
а как узнать что json не одной посылкой пришел?(ну понятно, скобки считываем) и если вторая посылка, то она снова с заголовками или просто через какое-то время приходит? т.е просто повторяем цикл с 54 по 58?
а как узнать что json не одной посылкой пришел?(ну понятно, скобки считываем) и если вторая посылка, то она снова с заголовками или просто через какое-то время приходит? т.е просто повторяем цикл с 54 по 58?
ну если начало json пришло, а скобок закрывающих нет - значит ждем следующей посылки
через какое то время могут прийти данные, причем размер данных не предсказуем, в вашем примере размер строки уже 429 байт, может тупо не влазит в какую либо переменную или память....
Такие вещи обрабатываются online - принимаете некое ключевое слово, например "sunrise", значит далее идет строка с данными, заносите в переменные, очищаете входной буфер, ждете приема другой ключевой фразы и т.д.
добавил после 62 строки
delay(1000); String line3; while ( client.available() ) { char c = client.read(); line3 += c; } Serial.print("line3= "); Serial.println(line3);получил
chitaem dannie line2= {"time":1565615641942,"clocks":{"11207":{"id":11207,"name":"Kopeysk","offset":18000000,"offsetString":"UTC+5:00","showSunriseSunset":true,"sunrise":"05:20","sunset":"20:35","isNight":false,"skyColor":"#7ac2f1","weather":{"temp":24,"icon":"bkn-d","link":"https://yandex.ru/pogoda/kopeysk"},"parents":[{"id":11225,"name":"Chelyabinsk Oblast"},{"id":225,"name":"Russia" line3= deserializeJson() failed: IncompleteInputт.е там больше ничего нет.
через какое то время могут прийти данные, причем размер данных не предсказуем, в вашем примере размер строки уже 429 байт, может тупо не влазит в какую либо переменную или память....
похоже на переполнение буфера.
а если тот же запрос сделать не ардуиной, а из браузера - приходит все?
это самая общая диагностика, она не гарантирует отсутсвие проблем. Памяти может быть дофига, но буфер обьявлен фиксировано - и в данные в него не входят.
а если тот же запрос сделать не ардуиной, а из браузера - приходит все?
да все приходит
Памяти может быть дофига, но буфер обьявлен фиксировано - и в данные в него не входят.
чтото не нашел, где задается размер буфера для wifi клиента...
а если тот же запрос сделать не ардуиной, а из браузера - приходит все?
да все приходит
ну тогда точно проблема в вашем коде. Либо не успеваете принимать, либо буфера не хватает, либо что-то еще. Может код слишком медленный и часть приходящих теряет
Коллеги, это ЕСП, туда всё влезет. Нужно аккуратно парсить. Для ЕСП есть прекрасный JSON парсер. Ищи на гитхабе.
Коллеги, это ЕСП, туда всё влезет. Нужно аккуратно парсить. Для ЕСП есть прекрасный JSON парсер. Ищи на гитхабе.
у этой библиотеки есть метод
где client - это wifi клиент, только у меня мозгов не хватило его победить. выдает ошибку.
точно что-то с размером буфера связано, т.к поставил другой регион - работает
chitaem dannie line2= {"time":1565670149987,"clocks":{"213":{"id":213,"name":"Moscow","offset":10800000,"offsetString":"UTC+3:00","showSunriseSunset":true,"sunrise":"04:56","sunset":"20:11","isNight":false,"skyColor":"#add0ff","weather":{"temp":15,"icon":"skc-d","link":"https://yandex.ru/pogoda/moscow"},"parents":[{"id":225,"name":"Russia"}]}}} line3= 0ff","weather":{"temp":15,"icon":"skc-d","link":"https://yandex.ru/pogoda/moscow"},"parents":[{"id":225,"name":"Russia"}]}}} Tekuschie data i vremya: 13.08.2019 07:22:29 Voshod v 04:56 Zakat v 20:11 Temperatura: 15 C Yasno Svetloe vremya sutokстрока длинной 325 символов работает, а 375 - нет. как увеличить буфер?
Парсить строку online
это конечно правильней, но победил пока так, а именно поставил библиотеку ArduinoJson-5.13.5 более ранней версии вот рабочий код.
классное табло. Три матрицы вертикально, если я правильно вижу?
классное табло. Три матрицы вертикально, если я правильно вижу?
нет одна 64х32
похоже придется переписывать, погоду и время запрашиваю раз в 10 минут, 10 раз опрашиваю, если неудачно, жду еще 10 мин.
andycat а можно пример online обработки, а то мне этот "интернет вещей" туго дается.
andycat а можно пример online обработки, а то мне этот "интернет вещей" туго дается.
нету примера :(
т.к. такой конкретной задачи никогда не делал.
Тупо поиск ключевой подстроки в буфере и данных после них, поищите в инете - наверняка масса примеров "парсить входящую строку модема". Вот старый похожий пример - кольцевой буфер размером с длину команды, но комментариев мало, без бутылки разобраться сложно.
http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-nim-svyazano?page=1#comment-439631
Upd: вот из последнего, читаются входные данные до конца строки (в вашем случае до какого то символа), потом уже обрабатывается буфер, после успешной обработки или ограничения по таймеру очищается буфер и дальше читаются данные.
void loadDataFromModem() { // load data from modem to buf - only one line (string) if (Serial.available()) { byte br; while (Serial.available()) { br = Serial.read(); if (br) { if (pos_buf >= (max_size_resp_buf - 1)) pos_buf = 0; resp_buf[pos_buf] = br; ++pos_buf; if (br == '\n') if ((pos_buf > 1) && (resp_buf[pos_buf - 2] == '\r')) break; // new string*/ } } resp_buf[pos_buf] = 0; // stop byte of string } }andycat перечитал 4 раза... пойду лучше напьюсь... всегда считал себя неглупым человеком, но перед многими из этого форума снимаю шляпу, всех перечислять не буду, но Вы в этом списке!
пойду лучше напьюсь...
правильно, я всегда так делаю
пойду лучше напьюсь...
правильно, я всегда так делаю
Деда Чин-Чин. Со всем уважением.
может кому пригодиться, парсим напрямую, без библиотеки Json