В предыдущей статье цикла о Kincony KC868-A4 было рассмотрено «атомарное» программирование компонентов этого контроллера, в этой статье будем разбирать более продвинутый пример работы с KC868-A4 — управление вашей (IoT) системой через интернет.

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

Ну и, конечно, когда вы добавите к основной функциональности вашего контроллера ещё и удалённое управление, то возможности вашей системы выйдут на совсем другой, более высокий, уровень.

▍ Как устроено управление через Telegram


Для непосвящённого человека такая вещь, как «управление контроллером через Telegram» выглядит чем-то не совсем понятным, сродни магии. Тем более управление Ардуино-контроллером через Telegram — что и как там работает, на первый взгляд, совершенно непонятно. На самом деле всё довольно просто — смартфон и контроллер обмениваются информацией, а Telegram в этой схеме выступает посредником между ними.



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

Telegram, как система, имеет множество возможностей, одной из которых являются так называемые «боты». Бот — это программный робот, который может взаимодействовать с пользователями через интерфейс Telegram и в данном случае мы будем использовать такого бота для организации управления контроллером Kincony KC868-A4.

Условно, вышеприведённую схему можно представить так:



Всё взаимодействие Telegram и контроллера (Kincony KC868-A4) скрыто от пользователя, он на экране своего смартфона видит только реакцию бота на свои действия. Тут важный момент, который нужно хорошо понимать: интерфейс бота обеспечивает Telegram, а вот специфическую «контроллерную» реакцию (действия, ассоциированные с контроллером) обеспечивает сам контроллер (в нашем случае Kincony KC868-A4).

Примечание. Кстати, в более привычных для вас случаях различных (публичных) ботов в Telegram, там, где у нас на схеме присутствует контроллер, находятся различные «взрослые» компьютерные системы, которые и обеспечивают функциональность этих ботов.

Если вы внимательно прочитали всё вышеизложенное, то вам должно стать в целом понятно как работает подобное управление через мессенджер Telegram (или любой другой). Теперь перейдём к разбору различных нюансов работы этой схемы.

▍ Безопасность


Взаимодействие между сервисом Telegram и вашим смартфоном является безопасным по умолчанию — разработчики в первую очередь позаботились об этом, поскольку мессенджер с небезопасным соединением не нужен никому.

А вот что касается соединения Telegram–Контроллер, то тут не всё так просто — это взаимодействие (через небезопасный интернет) нужно как-то защитить. И тут возникает два аспекта проблемы:



1. Нужно защитить само соединение. Поскольку мы используем микроконтроллер, то по умолчанию используются незащищённые соединения. Для решения этой проблемы нужно использовать специальную защищённую версию клиента (библиотеки).

2. Нужно идентифицировать наш контроллер, чтобы никто, кроме нашего контроллера, не смог управлять ботом. Эта проблема решается путём получения токена (специального уникального кода) в Telegram для доступа к нашему боту.

Далее мы более подробно остановимся на тонкостях обеспечения безопасности нашего Telegram–бота, а сейчас переходим от теории к практическим действиям и начнём мы с создания Telegram-бота, который будет управлять нашим контроллером.

▍ Создаём Telegram-бота


Чтобы создать бота для управления нашим контроллером, нам нужно воспользоваться услугами «папы» всех ботов в Telegram (BotFather). Для этого в строке поиска набираем «bot», находим BotFather и выбираем его.



При запуске BotFather предлагает небольшую справку и ссылки на подробную документацию и описание функций.



Сейчас нас эти подробности не очень интересуют и мы просто вводим первую команду «/start», на что BotFather отвечает списком управляющих команд.



Далее, воспользовавшись подсказкой BotFather, вводим команду для создания нового бота «/newbot».



Затем, на просьбу указать название нового бота, вводим название тестового бота для управления нашим контроллером KC868-A4 — «a4testbot».



И последний шаг — вводим username бота и получаем уникальный токен для управления им (на скриншоте сам токен скрыт, по понятным соображениям).



Собственно — всё, бота для управления контроллером Kincony KC868-A4 мы создали, теперь осталось только получить ваш ID пользователя Telegram для того, чтобы только вы могли управлять вашим контроллером (и никто другой).

▍ Получаем ID пользователя


Для того чтобы получить ID пользователя Telegram, нам нужно воспользоваться ещё одним ботом — IDBot. Находим его аналогично вышеописанному способу для BotFather и получаем следующее приветствие.



Вводим команду «/start» и получаем ваш ID пользователя для дальнейшего использования при программировании бота.



Теперь действительно всё, и мы можем переходить непосредственно к программированию нашего бота управления контроллером Kincony KC868-A4.

▍ Программирование


Это уже 3-я статья цикла о контроллере Kincony KC868-A4 и в предыдущих статьях мы подробно разбирали настройку среды программирования (Arduino) и рассматривали примеры «атомарного» программирования различных компонентов KC868-A4, поэтому перед дальнейшим чтением рекомендуем ознакомиться с предыдущими статьями этого цикла 1-я часть, 2-я часть (если вы ещё с ними не знакомы).

Для работы с API Telegram мы будем использовать специализированную библиотеку Universal-Arduino-Telegram-Bot, которая возьмёт на себя львиную долю трудозатрат по обеспечению взаимодействия нашего кода с сервисом Telegram и значительно облегчит и упростит нам задачу программирования нашего бота управления контроллером Kincony KC868-A4.

Нам также понадобится вспомогательная библиотека ArduinoJson, которая содержит необходимые функции работы с данными в формате Json.

На этом вступительную часть по программированию можно завершить и далее мы переходим непосредственно к составлению и разбору работы скетча нашего Telegram-бота.

▍ Скетч Telegram-бота


В качестве тестового примера управления контроллером Kincony KC868-A4 при помощи Telegram-бота мы будем реализовывать самый простой и наглядный сценарий работы — включение и выключение одного из реле контроллера командами в интерфейсе Telegram и запрос текущего статуса этого реле (ON/OFF).

Ниже приведён полный код нашего Telegram-бота, в котором вы должны изменить пустые данные на ваши реальные пароли, токены, названия Wi-Fi точек доступа и т. п., чтобы всё работало. Сначала вы должны внести в скетч ваши SSID и пароль от Wi-Fi.

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

Затем токен для управления ботом, получение которого мы рассмотрели выше.

#define BOTtoken "0000000000:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"

И ваш идентификатор в Telegram, получение которого мы тоже рассмотрели ранее.

#define CHAT_ID "0000000000"

Также нам нужно сделать некоторые дополнительные настройки в скетче. Задаём номер пина одного из четырёх реле Kincony KC868-A4 (см. схему и распиновку контроллера в предыдущих статьях).

const int ledPin = 2;

И сам код нашего Telegram-бота:

Полный код тестового примера управления контроллером Kincony KC868-A4

/*
  Kincony KC868-A4
  Telegram example
*/

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/telegram-control-esp32-esp8266-nodemcu-outputs/
 
  Project created using Brian Lough's Universal Telegram Bot Library: https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot
  Example based on the Universal Arduino Telegram Bot Library: https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot/blob/master/examples/ESP8266/FlashLED/FlashLED.ino
*/

#ifdef ESP32
  #include <WiFi.h>
#else
  #include <ESP8266WiFi.h>
#endif
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>   // Universal Telegram Bot Library written by Brian Lough: https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot
#include <ArduinoJson.h>

// Replace with your network credentials
const char* ssid = "ssid";
const char* password = "password";

// Initialize Telegram BOT
#define BOTtoken "0000000000:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"  // your Bot Token (Get from Botfather)

// Use @myidbot to find out the chat ID of an individual or a group
// Also note that you need to click "start" on a bot before it can
// message you
#define CHAT_ID "0000000000"

#ifdef ESP8266
  X509List cert(TELEGRAM_CERTIFICATE_ROOT);
#endif

WiFiClientSecure client;
UniversalTelegramBot bot(BOTtoken, client);

// Checks for new messages every 1 second.
int botRequestDelay = 1000;
unsigned long lastTimeBotRan;

const int ledPin = 2;
bool ledState = LOW;

// Handle what happens when you receive new messages
void handleNewMessages(int numNewMessages) {
  Serial.println("handleNewMessages");
  Serial.println(String(numNewMessages));

  for (int i=0; i<numNewMessages; i++) {
    // Chat id of the requester
    String chat_id = String(bot.messages[i].chat_id);
    if (chat_id != CHAT_ID){
      bot.sendMessage(chat_id, "Unauthorized user", "");
      continue;
    }
    
    // Print the received message
    String text = bot.messages[i].text;
    Serial.println(text);

    String from_name = bot.messages[i].from_name;

    if (text == "/start") {
      String welcome = "Welcome, " + from_name + ".\n";
      welcome += "Use the following commands to control your outputs.\n\n";
      welcome += "/led_on to turn GPIO ON \n";
      welcome += "/led_off to turn GPIO OFF \n";
      welcome += "/state to request current GPIO state \n";
      bot.sendMessage(chat_id, welcome, "");
    }

    if (text == "/led_on") {
      bot.sendMessage(chat_id, "LED state set to ON", "");
      ledState = HIGH;
      digitalWrite(ledPin, ledState);
    }
    
    if (text == "/led_off") {
      bot.sendMessage(chat_id, "LED state set to OFF", "");
      ledState = LOW;
      digitalWrite(ledPin, ledState);
    }
    
    if (text == "/state") {
      if (digitalRead(ledPin)){
        bot.sendMessage(chat_id, "LED is ON", "");
      }
      else{
        bot.sendMessage(chat_id, "LED is OFF", "");
      }
    }
  }
}

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

  #ifdef ESP8266
    configTime(0, 0, "pool.ntp.org");      // get UTC time via NTP
    client.setTrustAnchors(&cert); // Add root certificate for api.telegram.org
  #endif

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, ledState);
 
  // Connect to Wi-Fi
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  #ifdef ESP32
    client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Add root certificate for api.telegram.org
  #endif
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
  // Print ESP32 Local IP Address
  Serial.println(WiFi.localIP());
}

void loop() {
  if (millis() > lastTimeBotRan + botRequestDelay)  {
    int numNewMessages = bot.getUpdates(bot.last_message_received + 1);

    while(numNewMessages) {
      Serial.println("got response");
      handleNewMessages(numNewMessages);
      numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    }
    lastTimeBotRan = millis();
  }
}


Теперь кратко разберём основные части этого скетча. На функциях setup() и loop() мы останавливаться не будем — там всё стандартно и тривиально — в функции setup() производится инициализация и подключение к сети Wi-Fi, а в функции loop() производится постоянный мониторинг поступления новых сообщений от сервиса Telegram (от вас, как пользователя).

Основная функциональность бота реализуется в функции handleNewMessages(int numNewMessages), где в цикле обрабатываются поступившие сообщения.

for (int i=0; i<numNewMessages; i++) {

Производится проверка легитимности вашего подключения и игнорирование неавторизованных пользователей (с другими ID).

    // Chat id of the requester
    String chat_id = String(bot.messages[i].chat_id);
    if (chat_id != CHAT_ID){
      bot.sendMessage(chat_id, "Unauthorized user", "");
      continue;
    }

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

    String from_name = bot.messages[i].from_name;

    if (text == "/start") {
      String welcome = "Welcome, " + from_name + ".\n";
      welcome += "Use the following commands to control your outputs.\n\n";
      welcome += "/led_on to turn GPIO ON \n";
      welcome += "/led_off to turn GPIO OFF \n";
      welcome += "/state to request current GPIO state \n";
      bot.sendMessage(chat_id, welcome, "");
    }

Затем задаётся реакция на команды включения/выключения реле.

    if (text == "/led_on") {
      bot.sendMessage(chat_id, "LED state set to ON", "");
      ledState = HIGH;
      digitalWrite(ledPin, ledState);
    }
    
    if (text == "/led_off") {
      bot.sendMessage(chat_id, "LED state set to OFF", "");
      ledState = LOW;
      digitalWrite(ledPin, ledState);
    }

И реакция на запрос текущего статуса реле.

    if (text == "/state") {
      if (digitalRead(ledPin)){
        bot.sendMessage(chat_id, "LED is ON", "");
      }
      else{
        bot.sendMessage(chat_id, "LED is OFF", "");
      }
    }

Стоит ещё заметить, что для коммуникации с сервисом Telegram используется защищённая версия Wi-Fi клиента, чтобы обеспечить безопасность работы бота и управления контроллером.

#include <WiFiClientSecure.h>

Ну и наглядный результат работы нашего Telegram-бота в виде скриншота. Обратите внимание на последнюю команду «/state», которая не возымела никакого действия — это происходит при выключении (или недоступности по какой-либо причине) Arduino-контроллера — бот просто перестаёт отвечать на ваши команды в интерфейсе Telegram.



Как вы можете заметить, благодаря библиотеке Universal-Arduino-Telegram-Bot создание Arduino-ботов для управления вашими IoT системами через Telegram превращается в невероятно простое и доступное занятие — код предельно прост и прозрачен.

Отсюда следует и ещё один очень позитивный вывод: для того чтобы расширить базовую функциональность нашего тестового бота, вам не понадобятся какие-то особые познания в программировании — это сможет сделать даже начинающий любитель программирования и микроконтроллеров.

▍ Заключение


В этой статье мы рассмотрели продвинутый пример управления контроллером Kincony KC868-A4 через интернет при помощи Telegram-бота и выяснили, что это совсем несложно и доступно даже для начинающих любителей Arduino.

В следующей статье мы, наконец, доберёмся до «тяжёлой артиллерии» и познакомимся с примерами работы Kincony KC868-A4 под управлением комплексных ESP32-прошивок наподобие Tasmota, ESPhome или специализированной версии AMS.

P. S.

У компании Kincony есть Youtube-канал со множеством интересных примеров программирования и использования её продукции, в одном из роликов на этом канале описывается (правда, на английском языке и немного сумбурно) создание Telegram-бота.

Комментарии (11)


  1. PR200SD
    17.02.2022 13:02

    Тоже делал управление через TelegramBot, правда у меня концепция немного другая, не просто пункты, а формат команд для записи значений в сетевые регистры, таким образом я могу и читать и писать значения без привязки к конкретному алгоритму. Так же частично бот используется для получения информации о состоянии esp32 и настроек сервисов.


    1. smart_alex Автор
      17.02.2022 13:10

      В статье дан самый базовый пример работы для простоты понимания принципа, модифицировать код и (как угодно) расширить функциональность бота совсем несложно — на мой взгляд там всё элементарно...


      1. PR200SD
        17.02.2022 13:19

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


    1. PR200SD
      17.02.2022 13:20
      +2

      Вот мой вариант работы:


      1. smart_alex Автор
        17.02.2022 13:38
        +1

        Да, интересный ролик и интересный канал.


  1. dlinyj
    17.02.2022 13:08

    Какое потрясающее решение. Прям сразу миллионы идей, где это применить. Спасибо за статью!


    1. smart_alex Автор
      17.02.2022 13:11
      +1

      Всегда рад помочь... :)


  1. Delsian
    18.02.2022 13:15

    Если есть несколько одинаковых устройств, отличающихся, например, serial number'ом - как можно отдавать в боте команду конкретному устройству?


    1. smart_alex Автор
      18.02.2022 19:20

      Интересный вопрос... Первое что приходит в голову — каждому контроллеру — свой бот. Теоретически можно в команду вставлять идентификатор контроллера, а затем парсить такие команды, но что-то я сомневаюсь, что Telegram переварит кучу подключений (контроллеров) к одному боту.

      Если очень нужно — можно сделать шлюз Telegram — контроллеры, который и будет заниматься этой работой, но это как-то уж слишком заморочено.


    1. ra4hgn
      20.02.2022 08:22

      Если добавить в систему mqtt брокер, это будет не сложно. Не знаю правда если ли библиотека, с помощью которой контроллер может слать брокеру и читать сообщения брокера


      1. Delsian
        20.02.2022 11:53

        Ну так тогда уж проще AWS IoT - там и MQTT, и все нужные библиотеки. А на клауде поднять инстанс с ботом. Но это сильно все усложнит.