Главная » Arduino
Призовой фонд
на август 2022 г.
1. 1000 руб
Сайт Паяльник
2. Мультиметр ANENG M118A
Сайт Паяльник
3. 100 руб.

Интернет - советчик

При работе над очередным проектом чаще хочется сделать что-то полезное, что-то, что бы имело практическое применение в жизни и принесло пользу не только автору, но и другим людям. Но иногда хочется просто отдохнуть и сделать какую-нибудь забавную штуку, просто ради самого процесса, удовольствия и развлечения. Этим мы сегодня и займемся. 

Принцип работы устройства следующий: микроконтроллер подключается к WiFi сети, далее отправляет запрос к серверу (источнику сетевой мудрости), получает в ответ данные в формате json, далее разбирает ответ (парсит), перерабатывает в удобный вид и выводит на экран. Запрос нового совета по умолчанию происходит раз в десять минут, это время можно изменить в прошивке. Так же, если не терпится, можно получить свежий совет, нажав на кнопку. 

Итак, для начала нам нужен какой-либо сервис, у которого есть API, и желательно бесплатный. В сети есть много подобных ресурсов, которые предоставляют цитаты из книг, фильмов, случайные изображения и т.д. Я, в силу своей испорченности, выбрал сайт дающий интересные советы, но, правда, в немного грубоватой форме, вот этот.

Для изготовления устройства нам понадобятся следующие компоненты:

  • Микроконтроллер ESP8266 (Wemos d1 mini pro в моем случае)
  • Светодиодная матрица (8*8)*4 на базе MAX7219
  • Тактовая кнопка

Передавать данные на матрицу мы будем по интерфейсу SPI, значит надо разобраться к каким пинам нужно подключаться, взглянем на распиновку макетной платы:

 Для реализации подключения одного устройства по SPI необходимо четыре контакта: MOSI - передача данных ОТ УПРАВЛЯЮЩЕГО устройства к управляемому, MISO - от УПРАВЛЯЕМОГО к управляющему, CLK - линия тактирования, CS - выбор управляемого устройства. Так как нам нужно только отправлять данные на матрицу и не нужно ничего получать от нее обратно, то контакт MISO мы не используем.

Схема подключения панели предельно проста:

Итак, мы подключаем панель к микроконтроллеру следующим образом: CLK - D5, CS - D1, DIN (MOSI) - D7 ну и землю и питание к земле и +5в соответственно. Кнопка подключена к пину D2 и к земле. Потребление устройства небольшое, питать можно как от USB так и от внешнего источника питания. 

Пройдемся по коду, он как всегда довольно подробно прокомментирован, поэтому разобраться будет не сложно. На основных моментах остановимся подробней.

После объявления переменных и необходимых объектов, переходим к секции setup. Программа транслирует полученные данные как на светодиодный матричный экран, так и в монитор последовательного порта (на скорости 115200 бод), это удобно как для отладки, так и, например, для отслеживания истории полученной информации, а так как особого быстродействия от программы не требуется, то и работа контроллера по передаче данных в порт абсолютно не мешает. 

Не забываем перед прошивкой указать имя Вашей WiFi сети и пароль:

const char* ssid     = "Имя Вашей WiFi сети";     //ssid WiFi
const char* password = "Пароль Вашей WiFi сети";  //Пароль WiFi

Первым делом запускаем WiFi клиент и подключаемся к сети:

 WiFi.begin(ssid, password);
  matrix.fillScreen(LOW);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    service_message ("Link");                     //Индикация установки соединения
    wdt_count ++;
    if (wdt_count > 21) while (1);                //Перезагрузка через софтверный WDT если не удалось подключиться в течение 10 секунд 

Во время процесса подключения в монитор серийного порта раз в пол секунда выводится точка, а на матрице отображается сообщение Link. Т.к. при подключении иногда возникают непонятные проблемы (У ESP8266 они в принципе есть, и с ними приходится мириться, от этого никуда не деться), то после примерно 10 секунд, если подключение так и не произошло, запускается бесконечный цикл, что приводит к срабатыванию сторожевого таймера (WDT) и перезагрузке устройства.

Когда соединение наконец установлено, рапортуем об этом в порт и на светодиодный экран, и вызываем функцию jsonGet(); запрашивая первый совет:

  Serial.println("WiFi connected");
  service_message ("NetOK");                      //Есть соединение с сетью
  jsonGet();                                      //Запрашиваем первый совет

Рассмотрим саму эту функцию:

  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {          //Если сайт не отвечает, сообщаем об этом
    Serial.println("connection failed");
    service_message ("NoRes");
    delay (3000);
    return;
  }

Начинаем с того, что создаем объект WiFiClient и пытаемся подключится к серверу указанному в переменной host по 80 порту. Если это не удалось, сообщаем об этом в серийный порт и на дисплей. И выходим из функции до следующего раза (через 10 минут или до нажатия на кнопку). 

Если же подключение удалось, идем дальше и формируем и отправляем GET запрос для сервера:

  client.println("GET http://fucking-great-advice.ru/api/random"); //GET запрос
  client.println("Host: fucking-great-advice.ru");
  client.println("Connection: close");
  client.println();

  delay(1500);

У данного сервиса в описании указано несколько вариантов запросов:

/* Cлучайный совет */
http://fucking-great-advice.ru/api/random

/* Цензурная версия совета */
http://fucking-great-advice.ru/api/random/censored/

/* Советы по тегу */
http://fucking-great-advice.ru/api/random_by_tag/дизайн

/* Сегодняшний совет */
http://fucking-great-advice.ru/api/latest

/* Последние несколько советов */
http://fucking-great-advice.ru/api/latest/5

Однако на момент публикации работают только два варианта: это случайный совет и совет дня. Может, разработчики прочитают эту статью и наладят работоспособность остальных пунктов, но пока работаем с тем что есть, а именно с первым вариантом. 

После получения ответа сервера читаем его в переменную raw_string:
 

  while (client.available()) {
    raw_string = client.readStringUntil('\r');
  }

Разбираем ответ сервера с помощью метода библиотеки ArduinoJson (6 версии):

  StaticJsonDocument<512>  doc;                                  //Библитека ArduinoJson версии 6+
  DeserializationError error = deserializeJson(doc, raw_string); //десереализация из raw_string в doc
  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.f_str());
    return;
  }

Если разобрать не удалось, в монитор порта выводится сообщение об ошибке. Если все хорошо, идем дальше. Достаем поле "text" из ответа сервера, оно и содержит собственно сам совет, и сохраняем в переменную sovet типа String для дальнейшей обработки:

  String  sovet = doc["text"];                                  //Символы "—", "«", "»",отображаются некорректно, поэтому заменяем их если они есть. 
  sovet.replace("—", "-");
  sovet.replace("«", R"(")");
  sovet.replace("»", R"(")");

Как видно из кода, первоначальная обработка заключается в замене символов кавычек и тире, так как они некорректно отображаются при выводе на светодиодную панель (нюансы работы библиотеки Adafruit_GFX).

Далее совет подвергается безжалостной цензуре..

При желании эти строки можно удалить или закомментировать, а может дописать чего-то, что я мог пропустить, тут уже дело вкуса и эстетики. После чего меняется кодировка текста из UTF-8 в Windows-1251 посредством работы функции utf8rus, это необходимо для корректной работы библиотеки Adafruit_GFX и нормального отображения на экране кириллических символов. Готовый к отображению текст сохраняется в переменную raw_string, и отправляется в последовательный порт.

  raw_string = utf8rus(sovet);
  Serial.println(sovet);

Логика основного цикла программы довольно проста. После объявления всех переменных, создания необходимых объектов и подключения к сети, попадаем в основной цикл, где происходит следующее:
Обработка события нажатия кнопки (Нажатие обнаруживается через прерывание, чтобы избежать пропусков нажатия)

  butt1.tick();
  if (butt1.isClick()) {                           //При нажатии запрашиваем новые данные
    string_count = 0;
    jsonGet();
  }

Сбрасываем переменную string_count, чтобы новый совет отображался с начала фразы, и вызываем функцию jsonGet(); которая этот совет, собственно, запрашивает, получает и сохраняет в строковую переменную для вывода на экран.

Если нажатия не было, то то же самое делаем периодически, через заданный интервал времени (600000мс = 10 минут, по умолчанию ).

  if (millis() - tmr1 >= BASE_PERIOD) {            //Запрашиваем новые данные через установленный интервал времени
    tmr1 = millis(); 
    string_count = 0;                                     
    jsonGet();
  }

И выводим все это дело на экран с помощью функции output_on_display(), тут задержкой регулируется скорость прокрутки бегущего текста:

  if (millis() - tmr2 >= WAIT) {                   //Вывод совета бегущей строкой с установленной скоростью (задержкой)
    tmr2 = millis();                                      
    output_on_display (raw_string);
  }

На этом все. При желании скетч легко перенастраивается на другой похожий сервис, коих в сети не мало (Цитаты, афоризмы, погода, курсы валют.. и т.д.) Спасибо за внимание!

Список радиоэлементов

Обозначение Тип Номинал Количество ПримечаниеМагазинМой блокнот
LED дисплейMAX7219 (8x8) x 41 Поиск в магазине ОтронВ блокнот
МикроконтроллерWemos D1 Mini Pro1 Поиск в магазине ОтронВ блокнот
Кнопка тактовая1 Поиск в магазине ОтронВ блокнот
Добавить все

Скачать список элементов (PDF)

Прикрепленные файлы:

Теги:

Опубликована: 0 0
Я собрал 0 0
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 0 Проголосовало: 0 чел.

Комментарии (1) | Я собрал (0) | Подписаться

0
Публикатор #
На форуме автоматически создана тема для обсуждения статьи.
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется электрическая мощность?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Arduino UNO
Arduino UNO
Мультиметр DT9205A Лазерный модуль 650нм 5мВт
вверх