Обработать строку ArduinoJson по https
- Войдите на сайт для отправки комментариев
Собственно, как?
Есть вот такая строка:
{"status":200,"message":"rates","data":{"USDRUB":"63.1457","EURRUB":"68.9687"}}
Нужно достать курсы валют из неё.
С народным мониторингом разобрался, работает, вот функция:
void GetNarodmon() { char host[] = "narodmon.ru"; WiFiClient client; if (!client.connect(host, 80)) { Serial.println("connection failed"); return; } client.println(F("GET /api/sensorsValues?sensors=106470,106471&uuid=842e159496e712&api_key=8QM HTTP/1.1")); client.println(F("Host: narodmon.ru")); client.println(F("Connection: close")); if (client.println() == 0) { Serial.println(F("Failed to send request")); return; } // Check HTTP status char status[32] = {0}; client.readBytesUntil('\r', status, sizeof(status)); // It should be "HTTP/1.0 200 OK" or "HTTP/1.1 200 OK" if (strcmp(status, "HTTP/1.1 200 OK") != 0) { Serial.print(F("Unexpected response: ")); Serial.println(status); return; } // Skip HTTP headers char endOfHeaders[] = "\r\n\r\n"; if (!client.find(endOfHeaders)) { Serial.println(F("Invalid response")); return; } const size_t capacity = JSON_ARRAY_SIZE(2) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(6) + 170; DynamicJsonBuffer jsonBuffer(capacity); JsonObject& root = jsonBuffer.parseObject(client); if (!root.success()) { Serial.println(F("Parsing failed!")); return; } JsonObject& sensors_0 = root["sensors"][0]; float sensors_0_value = sensors_0["value"]; // 748.37 JsonObject& sensors_1 = root["sensors"][1]; float sensors_1_value = sensors_1["value"]; // -4.1 Serial.printf("Давление: %f\n", sensors_0_value); Serial.printf("Температура: %f\n", sensors_1_value); }
В монитор порта всё выводится, приделал так же и OpenWeather, всё аналогично. А вот ни с одним HTTPS сайтом работать не получается. Может, кто подскажет что сделать? У HTTPS 443 порт, это я знаю. Пробовал client объявить WiFiClientSecure, вроде как соединяется, но ничего парсить оттуда не желает. Все валютные сайты находятся на HTTPS.
Застревает на этой строке client.readBytesUntil('\r', status, sizeof(status));
Статус читать не хочет. Присылает ответ 400.
Я уже ненавижу тех, кто придумал этот проклятый https с этим самым fingerprint'ом...
Есть вот такая строка:
{"status":200,"message":"rates","data":{"USDRUB":"63.1457","EURRUB":"68.9687"}}
Нужно достать курсы валют из неё.
В монитор порта всё выводится ...
Так есть такая строка? Вы её получаете и печатаете в монитор порта? Я правильно понял? Или она только теоретически есть, а получить Вы её не можете?
Если она у Вас есть и в монитор порта печатается хорошо, то кто Вам мешает её распарсить как строку, а не вычитыванием из сети с помощью client.readBytesUntil?
Т.е. я не понял суть проблемы.
Не могу. Я так понимаю, проблема именно в https. Сайт - currate.ru.
Есть крайне кривая реализация, подсмотрел у AlexGyver'а. Там он берет библиотеку httpclient и добывает fingerprint со своего сайта, который (о, чудесное совпадение) просто http.
У базовых ардуино не хватит сил для работы с ssl. И где ты нашел инструкцию по работе с http вручную - пометь себе, чтобы больше никогда не соваться в эту помойку.
как получить сертификат с нужного сайта и использовать его в коде
https://techtutorialsx.com/2017/11/18/esp32-arduino-https-get-request/
ЗЫ - сам не пробовал
esp32
esp32
И что?
ТС ни словом не обмолвился, что у него за ардуина. А судя по тому, что он пытался использовать библиотеку WiFiSecure - у него либо 8266, либо ЕСП32
Если esp, то есть готовая https библиотека, и этим бредом тем более не надо заниматься.
У базовых ардуино не хватит сил для работы с ssl
Ну, разумеется у меня не ардуина, а ESP, о чём и говорят строчки WiFiClient в моём коде. :)
Примеры встречал, но они какие-то слишком специфичные, вроде для чтения строки с реддита, не очень понятно как переделать под свои нужды, хоть и пытался.
Понимаю, что fingerprint вручную - это кошмарный велосипед Франкенштейна, но по крайней мере так работает хоть...
Потом вот пример есть https://sprut.ai/client/article/224, но тоже не понимаю как его переделать.
Если esp, то есть готовая https библиотека, и этим бредом тем более не надо заниматься.
Можно подробнее?
https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266HTTPClie...
Да не, не то всё же, это видел уже. Fingerprint вручную вводят. А если действие сертификата прекратится, тогда что? Опять залезать в код программы и вписывать другой? Конечно, можно поднять домашний сервер для его получения, но это, сами понимаете, бред. Сейчас так сделано уже, но оно как-то то работает, то нет. ArduinoJson надежнее в этом плане.
ArduinoJson надежнее в этом плане.
надежнее чем? тем что надежно не работает? Вы вроде с этим на форум пришли?
Может быть откроешь документацию к библиотеке и посмотришь, не умеет ли она работать без фингерпринта? (подсказка: она умеет).
Причем тут arduinojson - я вообще хз, ты путаешь теплое с мягким.
Ну, у меня есть две реализации, одна через HTTPClient, другая - через Json и WiFiClient. Даже тот же http с народного мониторинга у первой нестабилен, проскакивают порой какие-то непонятные цифры.
Решил сделать через Json, столкнулся с проблемой https, вот и спрашиваю как сделать-то?
http://forum.amperka.ru/threads/esp8266-get-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81-%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D0%B8-%D1%81-%D1%81%D0%B0%D0%B9%D1%82%D0%B0.11284/
Тут вот Gyver даже спрашивает как сделать, я так понимаю он для своего проекта хотел запросы с гугла делать, но тоже столкнулся с SSL проклятущим. И сделал он эти запросы через костыли в виде своего сайта, где добывается fingerprint для HTTPS, я даже нашел этот проект. Так и что делать людям, у которых нет своего сайта? Поднимать свой? Вручную вписывать fingerprint?
Да
Да
Вы же несерьезно?)
Ну есть же реализации, тот же реддит, запрос для биткоинов. Как переделать под другой сайт эти примеры?
вот это https://sprut.ai/client/article/224
под сайт currate.ru
Раньше было только через фингерпринт.
Сейчас, говорят, можно без:
https://buger.dread.cz/simple-esp8266-https-client-without-verification-of-certificate-fingerprint.html
https://forum.arduino.cc/index.php?topic=643540.0
Если через сторонний сервер, то получить фингерпринт можно так (сорри, парсер обрамляет в <a>):
Спасибо, попробую.
Фингерпринт сейчас расшарен уже на локальном сервере, знаю как это, подсмотрел всё у того же Gyver'а PHP-код. Но это, повторюсь - большая ересь и дичь. С другой стороны, если посмотреть - это надо только мне, так что почему бы и нет... Только вот почему-то работает не очень стабильно. Иногда не успевает получить фингерпринт, а иногда ответ от сервера не приходит и вместо нормальных курсов пишет 0 и 1.99... Круто, обесцененные доллар и евро.)) narodmon и OpenWeather сделаны по примеру моего первого поста и здесь всё очень стабильно, ответ приходит всегда.
В общем, как говорится, есть хорошая новость и, естественно, плохая.
Работает этот код как надо, но лишь отдельно. Обрадовался сначала - "щас как внедрю, да как заработает!".
В моем большом проекте работать отказывается, уходит в ошибку Serial.printf("[HTTPS] GET... failed, error: %s\n\r", https.errorToString(httpCode).c_str());
С чем это связано? Без понятия, если честно. Даже в сетапе не хочет работать. Загоняю отдельно - работает. Поубирал из сетапа все свои функции кроме самых нужных - такая же ахинея, не работает и всё тут. Других реализаций HTTPclient в проекте больше нет.
Извините, что я немного не по теме. Вы утверждаете, что код в первом сообщении переделывается под OpenWaetherMap и успешно парсит прогноз на завтрашний день? Я просто сейчас уперся в реализацию выдергивания с помощью ArduinoJson данных из прогноза о погоде. Там просто вылетает огромная json-простыня по запросу и у моей ЕСП происходит банально overflow.
В моем большом проекте работать отказывается, уходит в ошибку Serial.printf("[HTTPS] GET... failed, error: %s\n\r", https.errorToString(httpCode).c_str());
С чем это связано?
может банально оперативки не хватает? JSON ответ в мегабайт или больше - обычное дело, а у вас в коде несколько запросов сразу...
Я конечно понимаю, что JSON это удобно, ничего знать не надо - но как оно обращается с памятью - точно не понятно. Парсить вручную может оказаться более эффективным, хотя конечно и более трудоемким
dizzel,
берете код json запроса и вставляете вот сюда и, собственно, всё. Вставляете полученный код в свой запрос и вместо переменной json (её можно вообще удалить) подставляете переменную из которой берется строка (в моём случае это client). Можно выводить переменные и делать с ними всё что угодно. Только обратите внимание на версию своей библиотеки arduinojson. Можно поступить еще проще, если Вам нужен только OpenWeather. Есть библиотека ESP8266_Weather_Station (по-моему, она есть в менеджере библиотек Arduino), можете в ней пример OpenWeatherMapCurrentDemo взять и сделать под себя.
b707,
понятно, попробую ESP32 взять. Возможно, 8266 не справляется с кучей кода и SSL запросом и даже json ни при чём. С fingerprint'ом опять же работает, но иногда не может получить и его с локального сервера. А вообще запросов немного ж: OpenWeather, narodmon и вот эта https валюта. С 3 запросами не справляется чтоль? При чём убирал OpenWeather и narodmon и всё равно не работает. Пробовал и другую реализацию через библиотеку ESP8266WiFi - отдельно работает тоже, а в общей программе так же не работает.
upd. Никто не знает случайно как на ESP32 сделать такой же защищенный запрос без фингерпринта? Библиотека ESP8266WiFi не работает с 32, а с WiFi.h ругается на BearSSL.
upd2. БИНГО! Разобрался. Достаточно использовать библиотеки WiFi.h и WiFiClientSecure.h. И без BearSSL всё работает в большой программе. Только вот проблема в том, что ESP32 - не Wemos.) Нужно кнопку нажимать(замыкать ногу) для прошивки. Придется курить OTA.
Да, я в курсе и про ArduinoJson и про ESP8266_Weather_Station. В первом варианте я не добился рабочего кода. В "Parsing program" парсится массив символов. Этот вариант отсек сразу. С массивом код вылетал с оверфлоу. Вариант с "serialize" не заработал. Ассистент для этого варианта не предлагает полного готового кода. Я пытался внедрить в него парсинг потока. Не заработало. В интернете есть примеры и инфа работы с разными версиями этой библиотеки, а для последней ничего этого нет, а она очень отличается.
ESP8266_Weather_Station вроде бы работает, но как она выдергивает прогнозы из сводки для меня загадка. Мне не удалось заставить ее парсить прогноз на следующий день на 12.00, например. Она предлагала 00.00, 09.00, 03.00 и т.д. и т.п. в разных комбинациях, но нужного не предлагала. Информации о том, как работает библиотека, что от чего зависит практически нет.
Однако выход я нашел. Это библиотека opeWeatherMap-ESP8266. Информации по ней тоже мало, но там хотя бы интуитивно понятно что делать чтобы получить нужный результат.
Короче, не получается с этой библиотекой. Сама по себе отдельно она работает, в отдельно написанном скетче. Вставляю скетч в свой код и ничего. То есть в момент когда начинается обработка запроса происходит что-то не понятное. Перестает работать выдача данных в серийный порт. ЕСП просто пропускает вообще все строки (даже обычные) Serial.print и порт молчит.
Парсинг методом ArduinoJson текущей погоды у ЕСП проблем не вызывает. Там не так много данных.
Короче это мука.
Если парсить прогноз с ArduinoJson и брать код из ассистента в разделе "Parsing Program", то раскладывать не получается, так как судя по всему слишком большой объем информации. Массив const char* json оказывается пустым и все переменные с нулевыми значениями.
Пользоваться кодом из раздела "Serializing program" я просто не пойму как. Там не указывается что входит в функцию, т. е. что она берет из вне чтобы это потом распарсить. Я так понимаю это и есть метод парсинга из потока, но как его подсунуть не соображу.
Пожалуйста, подскажите мне, люди добрые. Я вообще не могу разобраться как это сделать, не хватает соображалки. Прошу вас подскажите как выпарсить уже этот треклятый прогноз.
dizzel,
а что мешает сделать выборку из парсера?
Не обязательно забирать все данные из полотна, это точно ни к чему. Возьмите из того запроса только те данные, которые Вам нужны.
Вот, например, на завтра это list[9] из запроса api.openweathermap.org/data/2.5/forecast?q=Moscow&appid=[ВАШ_API]&units=metric верно?
Так и берите только list[9] с нужной переменной.
Пользоваться кодом из раздела "Serializing program" я просто не пойму как.
Этот раздел, насколько я понимаю, нужен для вывода данных на какую-либо веб-страницу в esp. То есть наоборот, обратный парсинг (возможно, ошибаюсь и тут подскажут знатоки библиотеки arduinojson). Но в любом случае Вам нужен именно "Parsing program".