Restarting an ESP32 via Telegram

Whoops, quite a long time with no posts!

Apologies for that, but it’s been a busier-than-usual year at Haaga-Helia UAS and especially the Haaga-Helia 3D + Robo Lab.

Speaking of which, there is a new system in place where the lab status can be seen online. The user interface looks like this:

The display for the lab status system

I have an ESP32 with a BMP280 air pressure / temperature sensor, CCS811 carbon dioxide / volatile organic compounds sensor, two passive infrared sensors for monitoring table occupancy, and a mechanical switch reporting the door status. All this data is sent to a MySQL data every minute, and is available for mining. There is also an LCD display to act as a local user interface. Lots of lovely wires everywhere, of course.

I have found that the BMP280 is sometimes reporting 179 degrees C in the lab, which is about twice the heat in a normal Finnish sauna, and that is not very likely to be reality at the lab. This used to happen rather often, and then the EP32 would get stuck. I first found that BMP280 is a dual mode sensor, with SPI and I2C, and to lock it into I2C which I am using required an extra wire. When you add one between the CSB (chip select bus) pin and 3.3V, the device does believe it must not stray between modes, and the errors decreased significantly.

How to restart the system remotely?

Even now I have seen some erroneous values, so I decided to see if it is possible to remotely turn the ESP on and off. Telegram then sprang to my mind, as I had seen it used in the annual IT Seminar for Students that we run with two or three other universities. Once more, Rui Santos came to my assistance with his massive ESP32 site, randomnerdtutorials.com. On that site you have examples on how to use Telegram with ESP32. All it takes is an account on Telegram, a bot set up there by the wonderfully named Botfather, and a library for Telegram functions on your development environment.

The way it works is that you tell your ESP32 what channel it should listen to, and which user is allowed in. Then system then checks what you sent as input and acts accordingly. Getting the device to return environmental data to me was rather easy, but getting it to reboot was not.

You see, I thought that I could just issue an ESP32.restart() command inside the Telegram message handler, but that leads into a boot loop, due to a mechanism I am not sure I fully understand. But what you can do is to set a variable inside the message handler the check for the value of it in the main loop, and if it is set to reboot, then use the restart command there.

I’ll use a simplified example file in this case. I’m writing a separate piece on the 3D + Robo Lab environmental sentinel. It’ll be out in three years or so.

Creating a Bot

All you need to do is to go to Telegram and join the service.

First, search for the IDBot and ask it to give you your user ID:

Then you can use the search and find Botfather, and issue the command /newbot (I have masked the proprietary parts, and the image is for a second bot I made for another purpose):

Here are the relevant bits of code:

#include <WiFi.h>
#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 = "PASSWD";

// Initialize Telegram BOT
#define BOTtoken "BOT:TOKEN"  // 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 "CHAT_ID"

UniversalTelegramBot bot(BOTtoken, client);  //create the bot object

// Checks for new messages every 200 milliseconds.
int botRequestDelay = 2000;
unsigned long lastTimeBotRan;

After this your ESP32 knows it has a channel for communicating.

A quick look at the setup() is also necessary:

void setup() {
  pinMode (13, OUTPUT);
  digitalWrite(13, LOW);
  Serial.begin(115200);
  // 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());
}

Next, you need a function that handles the incoming messages and acts on them. This simple example from randomnerdtutorial turns the LED on the board on and off with /lon and /loff, /start tells you all the commands available to you. Pay attention to the /reboot command and how it is handled.

void handleNewMessages(int numNewMessages) {
  Serial.println("handleNewMessages");
  Serial.println(String(numNewMessages));

  for (int i = 0; i < numNewMessages; i++) {
    Serial.print("i = ");
    Serial.println(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;
    if (text == "/reboot") {
      bot.messages[i].text = "/start";
    }
    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 += "/lon to turn on led \n";
      welcome += "/loff to turn off led\n";
      welcome += "/reboot to reset the ESP32\n";
      bot.sendMessage(chat_id, welcome, "");
    }

    if (text == "/reboot") {
      bot.sendMessage(chat_id, "ESP will now reboot.", "");
      forceBoot = 1;
    }

    if (text == "/lon") {
      digitalWrite(ledPin, HIGH);
      bot.sendMessage(chat_id, "LED is ON", "");
    }

    if (text == "/loff") {
      digitalWrite(ledPin, HIGH);
      bot.sendMessage(chat_id, "LED is OFF", "");
    }
  }
}

After this, in the loop, all you do is listen for messages and handle them in the handleNewMessages() function. But when the message is /reboot, you send the Boolean forceBoot to 1. See what happens in the loop, if that variable is true:

void loop() {
  if (millis() > lastTimeBotRan + botRequestDelay)  {
    int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    if (forceBoot == 1) {
      forceBoot = 0;
      ESP.restart();
    }
    while (numNewMessages) {
      Serial.println("got response");
      handleNewMessages(numNewMessages);
      numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    }
    lastTimeBotRan = millis();
  }
}

So, if the number of new messages is increased by one, then see if forceBoot is true. If it is, reset it to false, issue the command ESP32.reboot() and enjoy the fruits of your labor as the ESP32 resets itself safely and only once.

Here’s a picture of the Lab Surveillance System’s evil backbone machine:

Loading

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.