Всем привет! Уже давно я писал о том, как сделал подсветку для комнатных цветов, которые жена перевезла ко мне в мастерскую. Подоконники в квартире категорически закончились.
Так вот. После многих месяцев аптайма электричество, таки, вырубили на несколько часов. Но я об этом не узнал. Интернет в мастерской с 3g модема, а интернет, нынче доступен не весь, мягко говоря. Вот и мой телеграм бот не нашёл способа донести мне прискорбные новости о том, что время сбилось, рабочая программа больше не выполняется и из света остался только светодиод на блоке питания.
Но дома в праздники мне не сиделось и я пошёл в мастерскую лепить АЦП, печатать всякое на 3д принтере и всякое такое. И я решил не ждать, пока что-то изменится и быстренько переехать на бота вконтакте.
Немного о ботах и ключах.
Вконтакте позволяет делать ботов и взаимодействовать с ними через свой API. Для этого нужно раздобыть ключ доступа - токен. Он может давать доступ к аккаунту, что, например, используют неофициальные клиенты, например Kate mobile( почти что официальный и мой любимый). Но это не особенно безопасно - мы даем доступ практически ко всему, что есть на аккаунте. Или можно использовать токен группы вконтакте. Это значительно лучше с точки зрения безопасности. Мы сможем переписываться с ботом не как с самим собой, а как с сообщениями группы.
Как получить токен?
- Создайте группу ВКонтакте - это можно сделать по кнопке справа на странице "сообщества"
- Управление →Настойки →дополнительно→ Работа с API → Создать ключ
- Отметьте права: messages, manage
- Скопируйте токен (начинается с vk1.a.)
- Узнайте Ваш VK ID - для того, чтобы бот понимал - пишут свои. Узнать можно нажав на Профиль → мои данные → Изменить в VK ID. И там он будет рядом с аватаркой.
Там жмем "создать ключ"
Далее вк удостоверится, что это точно Вы. И выдаст ключик.
Можно было особенно не замазывать - ключ ооочень длинный набор рандомных символов, который выходит далеко за пределы окошка.
Что дальше?
А дальше нужно сделать новую программу на наш esp и во фреймворке arduino - почему бы и нет. У меня это ESP8266. Не перепаивать же плату, которая работает на более современный контроллер. Но если кому-то будет нужно - могу адаптировать под ESP32 или даже сделать конфигуратор.
Начнем.
Первое, что хотелось бы улучшить по сравнению со скетчем из старой версии - добавить возможность конфигурации точки доступа - удержанием какой-нибудь кнопки при старте контроллера - запускать простую точку доступа с названием flower и паролем 12345678
Какую-то такую.
Сначала нужно придумать где это всё хранить. Можно пойти сложным путем и подмонтировать файловую систему, а можно воспользоваться простым ардуиновским эмулятором EEPROM и сохранить всё в структуру. Так же время на ESP лучше обновлять не через сторонний сервис, а брать в том же VK API.
// Структура сохраняет все настройки в EEPROM
struct Settings {
char ssid[32]; // SSID WiFi (макс 31 символ + \0)
char password[64]; // Пароль WiFi (макс 63 символа + \0)
char vk_token[256]; // Токен VK (длинный, начинается с vk1.a...)
char user_id[16]; // ID пользователя VK (только цифры)
uint8_t checksum; // Контрольная сумма для проверки целостности
};
Например в такую. При старте без нажатой кнопки просто брать настройки из нее.
О том как читать и писать в EEPROM, создавать точку доступа или подключаться к ней, выводить HTML - написано очень много всего. Чтобы не растягивать статью сосредоточимся на работе с API VK. А мою реализацию можно будет посмотреть по ссылке внизу статьи. Когда я всё доделаю =). А пока создадим простого ЭХО-бота. Мы ему слова - он нам его же.
Эхо-бот.
//Подключаем библиотеки для подключения к вайфай и парсинга сообщений.
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
//Вводим свои настройки
#define WIFI_SSID "YourWiFi"
#define WIFI_PASS "YourPassword"
#define VK_TOKEN "vk1.a.your_token"
#define USER_ID "123456789"
// Создаем объект client для безопасного HTTPS соединения
WiFiClientSecure client;
// ID последнего обработанного сообщения (чтобы не отвечать дважды на одно сообщение)
int lastMsgId = 0;
// Функция setup()
void setup() {
Serial.begin(115200);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) delay(500);
// Настраиваем клиент для HTTPS соединений. setInsecure() отключает проверку SSL сертификатов.Это нужно, потому что ESP8266 не умеет проверять сертификаты VK.В реальных проектах это небезопасно, но для теста подойдет.
client.setInsecure();
// Создаем объект http для отправки HTTP запросов
HTTPClient http;
// формируем сообщение
String url = "https://api.vk.com/method/messages.send?";
url += "access_token=" VK_TOKEN "&peer_id=" USER_ID;
url += "&message=Bot%20started&random_id=" + String(random(10000)) + "&v=5.199";
http.begin(client, url);
// Отправляем GET запрос
http.GET();
//закрываем соединение
http.end();
Serial.println("READY! Send message to VK");
}
//функция loop()
void loop() {
// Получаем сообщения
HTTPClient http;
String url = "https://api.vk.com/method/messages.getHistory?";
// '5.199' - это версия VK API
url += "access_token=" VK_TOKEN "&user_id=" USER_ID "&count=1&v=5.199";
http.begin(client, url);
if (http.GET() == 200) {
String json = http.getString();
JsonDocument doc;
deserializeJson(doc, json);
// Получаем ВСЕ данные о сообщении
int msgId = doc["response"]["items"][0]["id"];
String text = doc["response"]["items"][0]["text"].as<String>();
// 0 = входящее, 1 = исходящее
int out = doc["response"]["items"][0]["out"];
// Проверяем: 1) новое ли сообщение 2) входящее ли (не наше)
if (msgId > lastMsgId && out == 0) {
lastMsgId = msgId;
Serial.print("Новое входящее сообщение: ");
Serial.println(text);
// Проверяем, не ответ ли это на наше сообщение
if (!text.startsWith("You said:")) {
// Эхо
text.replace(" ", "%20");
String echoUrl = "https://api.vk.com/method/messages.send?";
echoUrl += "access_token=" VK_TOKEN "&peer_id=" USER_ID;
echoUrl += "&message=You%20said:%20" + text;
echoUrl += "&random_id=" + String(random(10000)) + "&v=5.199";
// Создаем еще один HTTP клиент для отправки ответа
HTTPClient echoHttp;
// Начинаем соединение и отправляем ответ
echoHttp.begin(client, echoUrl);
echoHttp.GET();
//закрываем соединение
echoHttp.end();
//пишем в порт что получилось
Serial.print("Ответ отправлен: ");
Serial.println(text);
} else {
Serial.println("Пропускаем, это ответ бота");
}
} else
// Выводим для отладки
if (out == 1) {
Serial.println("Это наше исходящее сообщение, пропускаем");
} else {
Serial.println("Сообщение уже обработано");
} } }
http.end();
// Ждем 2000 миллисекунд (2 секунды) перед следующей проверкой, чтобы не перегружать сервер.
delay(2000);
}
Ещё понадобится библиотека ArduinoJson. В Arduino IDE ее можно найти в менеджере библиотек.
Вот минимальная рабочая версия клиента. Может только в эхо. Очень много кода, который будет повторяться в более-менее крупном проекте. Нужно бы написать свою библиотеку-обертку. Ну и перейдем к тестам!
Загружаем, перезагружаем!
Заходим в наше сообщество.
Переходим в диалог
И тестируем.
Готово! Теперь у нас есть диалог с ботом в мессенджере вк. Хотя сообщение "Bot started" при старте системы и подключении к WiFi уже и само включило этот диалог. Всё работает через интернет, который раздается через телефон при доступных лишь белых списках.
Но! Эхо-бот - это не полноценная система управления. Даже больше - это вообще не она. И ещё этот скетч использует Short Poll - не особенно хороший метод. Мы спрашиваем у вк каждые две секунды не появилось ли новых сообщений. Не хорошо для управления чем-то. Да и слишком много спама. Гораздо лучше использовать Long Poll который так же поддерживается VK API, но реализуется чуть сложнее. Мы просим API ждать новое сообщение, но не дольше, например, 30 секунд, а потом просим опять и опять. Новые сообщения приходят мгновенно.
На этом сегодня всё. Исходник получился небольшим и его можно скопировать прям со страницы статьи для экспериментов. Если кому-то это будет интересно, то обсудить дальнейшее развитие проекта можно тут в комментариях или телеграм-чате группы. Всем спасибо за просмотр! Как обычно буду рад конструктивным комментариям. До свидания!