Hey, I'm Marco and welcome to my newsletter!
As a software engineer, I created this newsletter to share my first-hand knowledge of the development world. Each topic we will explore will provide valuable insights, with the goal of inspiring and helping all of you on your journey.
In this episode I want to show you how to create a bot that monitors a data source and notifies you on Telegram. I created the first version a few years ago and still use it now when I am interested in a particular event but don't feel like checking it periodically.
1) 🔥 Monitoring of computer temperature
During college, once I had taken an exam for a course, I used to frequently check the course webpage because that was where the professor posted exam results. After spending months and months in refreshing the pages of the exams I was taking I said to myself, but what if I invent a way to automatically check the page and send myself a notification in case the professor has uploaded the results?
I didn't even finish the question that I was already implementing the bot.
1) YOLO
I also used this approach for the last course of the master's degree in Machine Learning, in this case the goal was not to monitor information on the Web but on my computer.
Together with my group, we were to train a YOLO convolutional neural network, the dataset was composed of images collected by us that we had labeled by going to define bounding boxes around the road signs, the goal was that given an new image as input then the network would respond in output with the same image with the recognized road signs.
Network training requires a lot of computational effort, I decided to use my Dell XPS. After a few minutes the fans started, which still could not keep the computer temperature below 90 degrees. Since it was taking days, and I was afraid of melting it down, I said to myself, but why don't I monitor the temperature and in case it's too high send myself a notification? So I did, I would run a terminal command, parse the output with an awk to extract the temperature, and if above 75 degrees I would send myself a message on a Telegram channel.
After several experiments I arrived at this setup:
The fan was able to raise the temperature from 90 to 71 degrees, the notebooks put in that way improved by another 3 degrees to about 68 degrees.
The first few times I would create a call on Meet in which I would use my IPad to frame the pc screen, periodically go in with my phone and make sure of the temperature, I didn't want the absence of notifications to be due to the fact that I had burned the pc 😁
2)👨💻 Let's get down to practice
You can download all the code shown directly from my Github repository: https://github.com/marcomoauro/telegram-notifier
We are going to implement a bot that periodically notifies us of Rome's temperature by going to retrieve it by scraping it from a weather forecast site. Obviously you could go through some provider's public api, the goal of this post is to show you how to do it by scraping and then adapt it to your needs.
the steps we will follow will be:
Creation of the Telegram bot
Implementation of the data retrieval and notification script
Deployment on Heroku
Setup of a Cron job
1) Creation of the Telegram bot
We are going to create a bot on telegram, this will allow us to send messages from the bot directly to our account. To create it we have to use a bot created by Telegram called BotFather, this allows us to create personal bots and edit them.
Then start the bot, press on the command "/newbot" to start the creation process, and choose the name and username. In my case I put “Temperature Bot” and “temperature_scraping_bot” respectively.
If the creation is successful then we will receive a message that will contain the api_key, this allows us to impersonate the bot, let's keep it safe as if someone learns about it they could use our bot.
One last information we need is the “chat_id” where to send the message, so let's open a new chat with our bot, send it a message as "test":
now let's open this link https://api.telegram.org/bot<BOT_API_KEY>/getUpdates replacing <BOT_API_KEY> with the api_key of your bot, you will find a response in JSON. You just need to take the chat.id field as shown in the figure:
2) Implementation of the data retrieval and notification script
You can download all the code shown directly from my Github repository: https://github.com/marcomoauro/telegram-notifier
Let's create a new Node project, you can refer to this post:
Create the .env file based on the .env-template file by going to configure the environment variables:
TELEGRAM_BOT_KEY
TELEGRAM_CHAT_ID
TEMPERATURE_THRESHOLD (we need to specify the threshold below which to be notified of the temperature)
Create the file src/telegram.js which will expose the function to call the telegram api to send the message:
import axios from "axios";
import {strict as assert} from 'assert';
assert(process.env.TELEGRAM_BOT_KEY, 'TELEGRAM_BOT_KEY env is required, define it in .env file')
assert(process.env.TELEGRAM_CHAT_ID, 'TELEGRAM_CHAT_ID env is required, define it in .env file')
export const sendNotification = async (message = 'Ping 🏓') => {
const {body} = await axios.get(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_KEY}/sendMessage?chat_id=${process.env.TELEGRAM_CHAT_ID}&text=${message}`)
return body
}
Now we create the file src/scrapeTemperature.js which exposes a function that takes care of retrieving the temperature in rome by scraping a weather forecast site, and if it is below a threshold set by us it returns the message that will be sent on the chat along with a flag that will tell us whether to send the message or not:
import axios from "axios";
import * as cheerio from "cheerio";
import {strict as assert} from 'assert';
assert(process.env.TEMPERATURE_THRESHOLD, 'TEMPERATURE_THRESHOLD env is required, define it in .env file')
const TEMPERATURE_THRESHOLD = parseInt(process.env.TEMPERATURE_THRESHOLD)
export const scrapeTemperature = async () => {
const {data} = await axios.get(`https://www.ilmeteo.net/meteo_Roma-Europa-Italia-Roma--1-31010.html`)
const $ = cheerio.load(data);
const temperature_text = $('.dato-temperatura').text().trim();
const temperature = parseInt(temperature_text.replace(/\D/g, ''));
const to_notify = temperature < TEMPERATURE_THRESHOLD
const message = `Temperature in Rome is ${temperature}°C`;
return {to_notify, message}
}
For extracting data from the html page I used the cheerio library.
Create the src/index.js file that will take care of retrieving the temperature data and if necessary invoke the function to send the message on telegram:
import {sendNotification} from "./telegram.js";
import {scrapeTemperature} from "./scrapeTemperature.js";
export const start = async () => {
const {to_notify, message} = await scrapeTemperature()
if (to_notify) {
await sendNotification(message)
}
}
To finish we create the bin/trigger.js file that will act as a trigger for the execution of the process:
import {start} from "../src/index.js";
await start()
3) Deployment on Heroku
We will deploy our application on Heroku, so that the process runs in the background on a remote machine. Start from this base by downloading the project locally: https://github.com/marcomoauro/telegram-notifier
You can follow this guide that I recently published:
Remember to configure the environment variables in the "Settings" tab.
4) Setup of a Cron job
Now we need to introduce the mechanism that invokes our function periodically. To do this we can use the add-ons Heroku Scheduler. Let's add it to our project:
We add a new job, and configure it to run every 10 minutes by specifying as a command:
node bin/trigger.js
Once created you will find it in the list of jobs.
If the configuration is correct, you will receive after 10 minutes the message from the bot:
And that’s it for today! If you are finding this newsletter valuable, consider doing any of these:
🍻 Read with your friends — Implementing lives thanks to word of mouth. Share the article with someone who would like it.
📣 Provide your feedback - We welcome your thoughts! Please share your opinions or suggestions for improving the newsletter, your input helps us adapt the content to your tastes.
I wish you a great day! ☀️
Marco