Получаем прогноз погоды от Яндекс с помощью ESP8266
В данном руководстве научимся получать с серверов Яндекса данные о погоде и декодировать полученный  JSON файл с помощью библиотеки ArduinoJson.
Получаем прогноз погоды от Яндекс с помощью ESP8266
04.05.2024 в 15:37   3184 2
Версия для печати
logo

В данном руководстве научимся получать с серверов Яндекса данные о погоде и местоположении через HTTP GET запросы при помощи  ESP8266.  Декодировать полученный  JSON файл с помощью библиотеки ArduinoJson и выводить полученную информацию в монитор последовательного порта.

Краткая информация о HTTP запросах? 

Для начала определимся, что из себя представляет протокол HTTP. 

Протокол HTTP предназначен для обеспечения связи между клиентами и серверами. HTTP работает как протокол запроса-ответа между клиентом и сервером. Веб-обозреватель может быть клиентом, а приложение на компьютере, на котором размещается веб-узел, может быть сервером.

Пример: клиент (обозреватель) отправляет HTTP-запрос на сервер; Затем сервер возвращает ответ клиенту. Ответ содержит сведения о состоянии запроса, а также может содержать запрошенное содержимое.

Два часто используемых метода запроса-ответа между клиентом и сервером: Get и POST.

  • GET - Запрашивает данные из указанного ресурса
  • POST - Отправка данных для обработки в указанный ресурс

Метод Get

Обратите внимание, что строка запроса (пары «имя-значение») отправляется в URL-адрес запроса GET:

/test/demo_form.php?name1=value1&name2=value2

Что вам нужно знать о GET запросах:

  • GET запросы могут кэшироваться
  • GET запросы остаются в истории браузера
  • GET запросы могут быть закладками
  • GET запросы никогда не должны использоваться при работе с конфиденциальными данными
  • GET запросы имеют ограничения по длине
  • GET запросы должны использоваться только для извлечения данных

Метод POST

Обратите внимание, что строка запроса (пары «имя-значение») отправляется в теле HTTP-сообщения запроса POST:

POST /test/demo_form.php HTTP/1.1
Host: html5css.ru
name1=value1&name2=value2

Что вам нужно знать о запросах POST:

  • POST запросы никогда не кэшируются
  • Запросы POST не сохраняются в журнале обозревателя
  • Запросы POST не могут быть закладками
  • Запросы POST не имеют ограничений по длине данных
На самом деле видов HTTP гораздо больше, но в рамках данного урока мы не будем их рассматривать.

 

Подготовка

 


Для получения данных о погоде и местоположении с сервером Яндекс нам понадобится лишь макетная плата на основе ESP8266, WiFi сеть с доступом в интернет, установленная на компьютере Arduino IDE и USB кабель для прошивки. Макетная плата подойдет любая Wemos D1 Mini, NodeMCU и т.п. Также для получения данных о погоде вам необходимо узнать код своего региона. Для этого перейдите на сайт ya.ru и в строке поиска напишите любой запрос.

запрос

Теперь обращаем внимание на адресную строку.

код региона

Значение после lr= и будет вашим кодом региона. В моем случае код региона 10646

 

Установка библиотеки ArduinoJSON

 


Также для декодирования полученного JSON файла нам понадобится библиотека ArduinoJSON 6 версии. Для ее установки запускаем ArduinoIDE и переходим в Инструменты > Управлять библиотеками. В окрывшемся Менеджере библиотек находим ArduinoJson, выбираем версию не ниже 6.0 и устанавливаем её.

arduinoJSON

На этом подготовительный этап закончен и можно переходить к прошивке

 

Прошивка устройства

 


Копируем в ArduinoIDE следующий код программы и прошиваемся
 
 

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

const char* ssid = "ssid";
const char* password = "pass";

// Код вашего региона в Яндекс
String regionID = "10646";

/* Инициализация таймеров. Чтобы ваш IP не забанил Яндекс запросы нельзя отсылать слишком часто. Поэтому будем делать это раз в 10 секунд */
unsigned long lastTime = 0;
// Устанавливаем таймер на 10 секунд (10000)
unsigned long timerDelay = 10000;

StaticJsonDocument<1000> doc;

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

 WiFi.begin(ssid, password);
 Serial.println("Connecting");
 while(WiFi.status() != WL_CONNECTED) {
 delay(500);
 Serial.print(".");
 }
 Serial.println("");
 Serial.print("WiFi подключен. ваш IP: ");
 Serial.println(WiFi.localIP());
 
 Serial.println("Устанавливаем таймер на 10 секунд. Ждем 10 секунд до первого чтения данных");
}

void loop() {
 // Отправляем HTTP GET запрос
 if ((millis() - lastTime) > timerDelay) {
 // Check WiFi connection status
 if(WiFi.status()== WL_CONNECTED){
 String serverPath = "https://yandex.com/time/sync.json?geo=" + regionID;
 
 WiFiClient client;
 HTTPClient http;
 http.begin(client,serverPath);
 int httpCode = http.GET();

 if (httpCode > 0) { 

 String response = http.getString();

 Serial.println(response);
 // Deserialize the JSON document
 DeserializationError error = deserializeJson(doc, response);

 // Проверяем успешность парсинга.
 if (error) {
 String errorStr = error.c_str();
 Serial.println(errorStr);
 }else{
 Serial.println("deserializeJson() без ошибок.");
 
 long long time = doc["time"]; // 1673807964173
JsonObject clocks_10646 = doc["clocks"]["10646"];
int id = clocks_10646["id"]; // 10646
Serial.println("ID="+id);
const char* name = clocks_10646["name"]; // 
Serial.println("Город: "+String(name));
const char* offsetString = clocks_10646["offsetString"]; 
Serial.println("Часовой пояс: "+String(offsetString));
const char* sunrise = clocks_10646["sunrise"];
Serial.println("Рассвет: "+String(sunrise));
const char* sunset = clocks_10646["sunset"]; 
Serial.println("Закат: "+String(sunset));

JsonObject clocks_10646_weather = clocks_10646["weather"];
int weather_temp = clocks_10646_weather["temp"]; // -5
Serial.println("Температура воздуха: "+String(weather_temp));
const char* clocks_10646_weather_icon = clocks_10646_weather["icon"]; 
const char* clocks_10646_weather_link = clocks_10646_weather["link"];

for (JsonObject clocks_10646_parent : clocks_10646["parents"].as<JsonArray>()) {
 const char* parent_name = clocks_10646_parent["name"]; 
 Serial.println("Местоположение: "+String(parent_name));
 
 }
 }
 } else{
 Serial.println("http.GET() == 0");
 }
 
 http.end(); //Закрываем соединение
 }
 else {
 Serial.println("WiFi отключен");
 }
 lastTime = millis();
 }
}
 

 

Как работает код

 

Сначала подключаем необходимые библиотеки


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

Далее пишем учетные данные для подключения к вашей сети WiFi


const char* ssid = "ssid";
const char* password = "pass";

SSID меняем на имя своей точки доступа, pass - на свой пароль

Далее указываем свой код региона в Яндекс. Как его получить было рассмотрено на предыдущем шаге


// Код вашего региона в Яндекс
String regionID = "10646";

Далее идет инициализация таймера. Все дело в том, что слишком большое число GET запросов к серверу за единицу времени может привести к тому, что рано или поздно ваш IP адрес окажется в черном списке. Поэтому чтобы ваш IP не забанили будет отправлять запросы не чаще чем раз в 10 секунд. В идеале лучше еще реже. Например раз в 30 секунд или раз в минуту.


/* Инициализация таймеров. Чтобы ваш IP не забанил Яндекс запросы нельзя отсылать слишком часто. Поэтому будем делать это раз в 10 секунд */
unsigned long lastTime = 0;
// Устанавливаем таймер на 10 секунд (10000)
unsigned long timerDelay = 10000;

Далее выделяем память под наш JSON файл

StaticJsonDocument<1000> doc; 

На самом деле размер полученного JSON файла от Яндекс примерно около 800 байт. Но иногда он может изменяться в большую или меньшую сторону. Поэтому выделим память с небольшим запасом - 1000 байт

 

Блок настроек Setup()

 

В данном блоке открываем последовательный порт на скорости 1155200 Бод и подключаемся к точке доступа

 

Основной цикл программы loop()

 

В основном цикле программы мы раз в 10 секунд проверяем наличие подключения к WiFi сети и если оно доступно отправляем GET запрос на сервер погоды Яндекс

// Отправляем HTTP GET запрос
 if ((millis() - lastTime) > timerDelay) {
 // Check WiFi connection status
 if(WiFi.status()== WL_CONNECTED){
 String serverPath = "https://yandex.com/time/sync.json?geo=" + regionID;
 
 WiFiClient client;
 HTTPClient http;
 http.begin(client,serverPath);
 int httpCode = http.GET();

Далее проверяем код ответа сервера на запрос файла https://yandex.com/time/sync.json?geo=" + regionID Он хранится в переменной httpCode. Если он прошел успешно, т.е ответ сервер выдал в ответ код ответа больше 0, то пробуем прочитать содержимое файла в переменную response.

if (httpCode > 0) { 

 String response = http.getString();

 Serial.println(response);

Теперь пробуем расшифровать полученный JSON файл, хранящийся в переменной response

// Deserialize the JSON document
 DeserializationError error = deserializeJson(doc, response);

 // Проверяем успешность парсинга.
 if (error) {
 String errorStr = error.c_str();
 Serial.println(errorStr);
 }else{
 Serial.println("deserializeJson() без ошибок.");

Если были ошибки расшифровки, то выводим их монитор последовательного порта. Если нет, то приступаем к чтению значений и выводим их на экран

long long time = doc["time"]; // 1673807964173
JsonObject clocks_10646 = doc["clocks"]["10646"];
int id = clocks_10646["id"]; // 10646
Serial.println("ID="+id);
const char* name = clocks_10646["name"]; // 
Serial.println("Город: "+String(name));
const char* offsetString = clocks_10646["offsetString"]; 
Serial.println("Часовой пояс: "+String(offsetString));
const char* sunrise = clocks_10646["sunrise"];
Serial.println("Рассвет: "+String(sunrise));
const char* sunset = clocks_10646["sunset"]; 
Serial.println("Закат: "+String(sunset));

JsonObject clocks_10646_weather = clocks_10646["weather"];
int weather_temp = clocks_10646_weather["temp"]; // -5
Serial.println("Температура воздуха: "+String(weather_temp));
const char* clocks_10646_weather_icon = clocks_10646_weather["icon"]; 
const char* clocks_10646_weather_link = clocks_10646_weather["link"];

for (JsonObject clocks_10646_parent : clocks_10646["parents"].as<JsonArray>()) {
 const char* parent_name = clocks_10646_parent["name"]; 
 Serial.println("Местоположение: "+String(parent_name));

И, наконец, в случае если http GET запрос все же вернул ошибку, то закрываем соединение, перезапускаем таймер и начинаем цикл сначала



} else{
 Serial.println("http.GET() == 0");
 }
 
 http.end(); //Закрываем соединение
 }
 else {
 Serial.println("WiFi отключен");
 }
 lastTime = millis();
 }
}

 

Проверка результата

 

Запускаем ArduinoIDE, открываем монитор последовательного порта, выставляем скорость 115200 и если все прошло удачно вы должны увидеть следующий результат

com port

Материал также доступен на моем канале: Яндекс Дзен и в группе ВК
Категория: Программирование | Добавил: :, (15.01.2023)
Просмотров: 3184 | Комментарии: 2 | Теги: Arduino IDE, Яндекс погода, ESP8266, ArduinoJSON | Рейтинг: 0.0/0
Поделиться:
Всего комментариев: 2
avatar
0
Денис • 13:14, 27.01.2023
Добрый день!
при компиляции выходит ошибка for (JsonObject clocks_10646_parent : clocks_10646["parents"].as()
если закоментировать, то выдает тока сырой поток инфы ArduinoJson-6.20
avatar
0
ALT • 13:59, 05.02.2023
Здравствуйте. При вставке на сайт кода содержимое в угловых скобках стало восприниматься как html тег
Правильное написание будет таким
Код
for (JsonObject clocks_10646_parent : clocks_10646["parents"].as<JsonArray>))

В статье исправил.
avatar