Найти тему
Project A.L.T.

Получаем прогноз погоды от Яндекс с помощью ESP8266

Оглавление

В данном руководстве научимся получать с серверов Яндекса данные о погоде и местоположении через 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 и в строке поиска напишите любой запрос.

-2

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

-3

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

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

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

-4

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

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

Копируем в 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()) {
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()) {
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 и если все прошло удачно вы должны увидеть следующий результат

-5

Также с этой и другими статьями подобной тематики можно ознакомиться на https://projectalt.ru