При работе над очередным проектом чаще хочется сделать что-то полезное, что-то, что бы имело практическое применение в жизни и принесло пользу не только автору, но и другим людям. Но иногда хочется просто отдохнуть и сделать какую-нибудь забавную штуку, просто ради самого процесса, удовольствия и развлечения. Этим мы сегодня и займемся.
Принцип работы устройства следующий: микроконтроллер подключается к 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 4 | 1 | Поиск в магазине Отрон | |||
Микроконтроллер | Wemos D1 Mini Pro | 1 | Поиск в магазине Отрон | |||
Кнопка тактовая | 1 | Поиск в магазине Отрон | ||||
Скачать список элементов (PDF)
Прикрепленные файлы:
- Great_advice_prod.zip (3 Кб)
Комментарии (4) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация
[Автор]
[Автор]