DEV Community

Cover image for Building a Weather and Time Telegram Bot using Node.js
Chris Achinga
Chris Achinga

Posted on

Building a Weather and Time Telegram Bot using Node.js

Telegram bots are automated applications that run inside Telegram. Users can interact with bots by sending messages, commands, and inline requests. Today, we'll walk you through how to build a simple Telegram bot using Node.js that provides weather and time information for any city.

Prerequisites

Before we start, make sure you have the following:

  • Node.js and npm installed on your machine.
  • A Telegram account to create and manage bots.
  • An API key from OpenWeatherMap.

Setting Up Your Project

Firstly, install the required Node.js packages: **dotenv**, **node-telegram-bot-api**, **axios**, and **moment-timezone**.

npm install dotenv node-telegram-bot-api axios moment-timezone
Enter fullscreen mode Exit fullscreen mode
  • **dotenv**: To handle environment variables.
  • **node-telegram-bot-api**: To interact with the Telegram Bot API.
  • **axios**: To make HTTP requests to the OpenWeatherMap API.
  • **moment-timezone**: To handle time and timezones.

Creating the Bot

You'll need a bot token from Telegram. Use the BotFather to create a new bot and get the token. Save the token and your OpenWeatherMap API key in a **.env** file:

TELEGRAM_BOT_TOKEN=your_telegram_bot_token
OPENWEATHERMAP_API_KEY=your_openweathermap_api_key
Enter fullscreen mode Exit fullscreen mode

Image description

In your main JavaScript(app.js) file, initialize your bot and the storage object:

require('dotenv').config()

const TelegramBot = require('node-telegram-bot-api')
const axios = require('axios')
const moment = require('moment-timezone')

const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN
const OPENWEATHERMAP_API_KEY = process.env.OPENWEATHERMAP_API_KEY

const bot = new TelegramBot(TELEGRAM_BOT_TOKEN, { polling: true })
const storage = {}
Enter fullscreen mode Exit fullscreen mode

The **storage** object will keep track of the state of the conversation with each user.

Handling Commands and Callback Queries

Next, handle the **/start** command and present the user with two options: getting the weather or the time. We use an inline keyboard for this:

bot.onText(/\/start/, (msg) => {
  const chatId = msg.chat.id
  bot.sendMessage(
    chatId,
    'Hello! This bot can show you the weather and time for any city. To use it, please choose an option below:',
    {
      reply_markup: {
        inline_keyboard: [
          [{ text: 'Get Weather', callback_data: 'get_weather' }],
          [{ text: 'Get Time', callback_data: 'get_time' }],
        ],
      },
    }
  )
})
Enter fullscreen mode Exit fullscreen mode

The bot then listens for button presses and asks the user to enter the name of a city:

bot.on('callback_query', async (callbackQuery) => {
  const chatId = callbackQuery.message.chat.id
  const data = callbackQuery.data

  switch (data) {
    case 'get_weather':
      const userDataWeather = getUserData(chatId)
      userDataWeather.waitingForCity = true
      userDataWeather.waitingForWeather = true
      bot.sendMessage(chatId, 'Please enter the name of the city or send /stop to cancel:')
      break
    case 'get_time':
      const userDataTime = getUserData(chatId)
      userDataTime.waitingForCity = true
      userDataTime.waitingForTime = true
      bot.sendMessage(chatId, 'Please enter the name of the city or send /stop to cancel:')
      break
    default:
      break
  }
})
Enter fullscreen mode Exit fullscreen mode

Handling User Responses

The **getUserData** function initializes or retrieves the user's state from the **storage** object:

function getUserData(chatId) {
  let userData = storage[chatId]
  if (!userData) {
    userData = {
      waitingForCity: false,
      waitingForWeather: false,
      waitingForTime: false,
    }
    storage[chatId] = userData
  }
  return userData
}
Enter fullscreen mode Exit fullscreen mode

Then, the bot listens for a message from the user, which should be the city's name:

bot.on('message', async (msg) => {
  const chatId = msg.chat.id
  const text = msg.text

  const userData = getUserData(chatId)
  if (userData && userData.waitingForCity) {
    const city = text
    let messageText = ''
    if (userData.waitingForWeather) {
      messageText = await getWeatherData(city)
    } else if (userData.waitingForTime) {
      messageText = await getTimeData(city)
    }
    bot.sendMessage(chatId, messageText)
    resetUserData(chatId)
  }
})
Enter fullscreen mode Exit fullscreen mode

We reset the user data after sending the response, so the bot is ready for the next command. The **resetUserData** function looks like this:

function resetUserData(chatId) {
  const userData = getUserData(chatId)
  userData.waitingForCity = false
  userData.waitingForWeather = false
  userData.waitingForTime = false
}
Enter fullscreen mode Exit fullscreen mode

Fetching the Weather and Time Data

The **getWeatherData** function fetches weather data from the OpenWeatherMap API:

async function getWeatherData(city) {
  const response = await axios.get(
    `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${OPENWEATHERMAP_API_KEY}`
  )
  const weatherData = response.data
  const weatherDescription = weatherData.weather[0].description
  const temperature = Math.round(weatherData.main.temp - 273.15)
  const messageText = `The weather in ${city} is currently ${weatherDescription} with a temperature of ${temperature}°C.`
  return messageText
}
Enter fullscreen mode Exit fullscreen mode

The **getTimeData** function gets the current time in the city's local timezone using moment-timezone:

async function getTimeData(city) {
  const response = await axios.get(
    `http://api.geonames.org/timezoneJSON?formatted=true&lat=${city.lat}&lng=${city.lon}&username=demo&style=full`
  )
  const data = response.data
  const localTime = data.time
  const messageText = `The current time in ${city} is ${localTime}.`
  return messageText
}
Enter fullscreen mode Exit fullscreen mode

Running The Bot

Update your package.json file to run the bot:

  "scripts": {
    "start": "node app.js"
  },
Enter fullscreen mode Exit fullscreen mode

Run the command on a terminal:

npm start
Enter fullscreen mode Exit fullscreen mode

Open your Bot on the Telegram app to test it:

DEMO: Telegram Bot - YouTube

This simple Telegram bot provides weather and time information for a given city using the OpenWeatherMap API and the Moment Timezone library.

favicon youtube.com

Wrapping Up

This simple bot is a fun way to explore the capabilities of Telegram bots and Node.js. The bot could be expanded in numerous ways, such as supporting more commands, integrating more APIs, or adding a more sophisticated conversation state.

Remember to properly secure your API keys and tokens. Never expose them in your code or version control system. Instead, use environment variables or some form of secure secret management.

GitHub logo achingachris / telegram-helper

A telegram Bot that tells you time and weather

Telegram Bot(JavaScript) - Weather and Time Telegram Bot

This is a simple Telegram bot that provides weather and time information for a given city using the OpenWeatherMap API and the Moment Timezone library.

Table of Contents

  1. Features
  2. Getting Started
  3. Usage
  4. Environment Variables
  5. Dependencies
  6. License

Features

  • Retrieve weather information for a given city.
  • Retrieve the current time for a given city.

Getting Started

To get started with this project, follow the steps below:

  1. Clone the repository to your local machine.
  2. Install the required dependencies using npm install.
  3. Set up the required environment variables (see Environment Variables).
  4. Run the bot with node index.js.

Usage

To use the bot, follow these steps:

  1. Start the bot by sending the /start command.
  2. Choose an option by clicking either 'Get Weather' or 'Get Time'.
  3. Enter the name of the city when prompted.
  4. The bot will return the weather or time information for the…

Happy coding!

Top comments (1)

Collapse
 
dev-vickie profile image
Victor Mutethia

This is informative