Simple Telegram weather bot using Python/OpenWeatherMap/Wayscript

Create a simple weather notification bot using OpenWeatherMap and Wayscript to keep you prepared for the whole week ahead

In this simple python tutorial, we are going to use OpenWeatherMap API to gather the weeks forecast. And then we are going to use Wayscript to get the notification sent to our Telegram messenger daily. This Telegram weather bot will keep you prepared for the whole week. OpenWeatherMap and WayScript are both provide free tier for their online services so you do not have to spend any money to run this.

Screenshot of the message weather telegram bot message sent
The message weather telegram bot message sent

Most people will like to have their weather updates through apps, widgets and such. These days Android and iOS have smart assistants to show and even recite the weather forecast. For us in Nepal, where weather forecasts aren’t that accurate, they seem a bit much to waste battery on. So I decided to look out for a method to get a brief overview of the weekly weather forecast. Even it is not 100% accurate, it’s still based on statistics/data which can help prepare your week in advance.

Thankfully, guys at OpenWeatherMap provide a generous weather API from which you can request plenty of data. Even with the free tier, you can get 1000 requests per day. That is more than enough for amateurs like us. And Wayscript is an online development service that allows you to run and integrate multiple programming languages, online/social services and a lot more.

Getting started:

The code doesn’t depend on any external dependencies. It uses in-built python modules to request and parse the required data. The URL used to request the weather forecast only requests weekly forecast. It filters minutely/hourly forecast which we are not going to use. Before we dive right into the code. Here’s what you require:

  1. Wayscript Account
  2. OpenWeatherMap account and API key
  3. Your location’s latitude and longitude
  4. Telegram Bot API Token
  5. Telegram Chat ID where the notifications are sent

Check out our Telegram Bot API article to learn the basics of getting started with Telegram bots.

The code:

Fill in the required data to before you run it.

from urllib import request, parse
import json
from datetime import datetime

# Data required

lat = '' #latitude
lon = '' #longitude
appid = '' #openweather API token
units = 'metric' #unit of measurement (standard/metric/imperial)
tgbot = '' #telegram bot API token
tg_id = '' #Telegram chat id
msg = '' #initiate message to be combined later

# URL structure for OpenWeatherMap API

url = f'https://api.openweathermap.org/data/2.5/onecall?lat={lat}&lon={lon}&exclude=minutely,hourly&appid={appid}&units={units}'

# Get the weather forecast data from the OpenWeatherMap API
# Parse the json data into python readable format
# Assign it to 'data' variable

with request.urlopen(url) as rq:
   data = json.loads(rq.read().decode('utf-8'))

# Loop through the daily weather forecase to format data to our liking
# OpenWeatherMap sends a Unix timestamp which is converted to a readable date
# The data is enumerated to that today's result is visibilly separated from the rest
# M,D,E,N represent morning, day, evening, and night

for i, d in enumerate(data['daily']):
   day = datetime.utcfromtimestamp(int(d['dt'])).strftime('%a (%m-%d)')
   feels=d["feels_like"]
   sep = '\n\n' if (i == 0) else '\n'
   msg += f'{day}: {d["weather"][0]["description"].capitalize()}'+ '\n' +f'Feels: M-{feels["morn"]}, D-{feels["day"]}, E-{feels["eve"]}, N-{feels["night"]}' + sep

# Telegram BOT API HTTP request URL formatting
# Parse the message with parse.quote_plus to make URL legible

tg = f'https://api.telegram.org/bot{tgbot}/sendMessage?chat_id={tg_id}&text=' + parse.quote_plus(msg)

# Send the notification request
request.urlopen(tg)

Uploading it to Wayscript:

Wayscript is fairly straight forward. It uses a flow chart like blocks to play with different services. Create a new Project. You just have to add a timer trigger at the top with the Add Trigger button. Then on the left sidebar, select the time to run this on a specific time. And then add a Python block to include the code we just made. You can use the Open Editor button on the sidebar for a bigger view of the code. You can also test run the code to check if it is working. Don’t forget to turn on the Time Trigger so the toggle is green, or it wouldn’t run repeatedly.

Screenshot of Wayscript running the python code for weather notification

Finally,

This Telegram weather bot code is written in the simplest form without much manipulation of data and formatting. As temperature and other units are forecasts, we could round them up from floats to single integer with python’s round function. You could also parse the weather text to show some weather Unicode icons (☀️🌤️⛅☁️⛈️☔❄️) instead of text. But that depends on what you want to do with it. Check the JSON response from OpenWeatherMap to utilize other aspects of the forecast into your notification.

OpenWeatherMap One call API response JSON (for reference)

{
  "lat": 25.1234,
  "lon": 85.1234,
  "timezone": "Asia/Kathmandu",
  "timezone_offset": 20700,
  "current": {
    "dt": 1613534343,
    "sunrise": 1613523225,
    "sunset": 1613563823,
    "temp": 13,
    "feels_like": 11.67,
    "pressure": 1021,
    "humidity": 76,
    "dew_point": 8.87,
    "uvi": 4.33,
    "clouds": 20,
    "visibility": 2500,
    "wind_speed": 1.54,
    "wind_deg": 110,
    "weather": [
      {
        "id": 701,
        "main": "Mist",
        "description": "mist",
        "icon": "50d"
      }
    ]
  },
  "daily": [
    {
      "dt": 1613542500,
      "sunrise": 1613523225,
      "sunset": 1613563823,
      "temp": {
        "day": 19.68,
        "min": 6.34,
        "max": 21.03,
        "night": 8.49,
        "eve": 13.86,
        "morn": 6.42
      },
      "feels_like": {
        "day": 16.51,
        "night": 5.55,
        "eve": 10.51,
        "morn": 3.37
      },
      "pressure": 1017,
      "humidity": 27,
      "dew_point": 0.18,
      "wind_speed": 1.73,
      "wind_deg": 162,
      "weather": [
        {
          "id": 800,
          "main": "Clear",
          "description": "clear sky",
          "icon": "01d"
        }
      ],
      "clouds": 1,
      "pop": 0.12,
      "uvi": 7.45
    },
    {
      "dt": 1613628900,
      "sunrise": 1613609575,
      "sunset": 1613650265,
      "temp": {
        "day": 19.41,
        "min": 7.06,
        "max": 19.93,
        "night": 8.85,
        "eve": 14.42,
        "morn": 7.07
      },
      "feels_like": {
        "day": 15.88,
        "night": 5.88,
        "eve": 11.46,
        "morn": 4.07
      },
      "pressure": 1020,
      "humidity": 26,
      "dew_point": -1.65,
      "wind_speed": 2.08,
      "wind_deg": 155,
      "weather": [
        {
          "id": 800,
          "main": "Clear",
          "description": "clear sky",
          "icon": "01d"
        }
      ],
      "clouds": 0,
      "pop": 0.35,
      "uvi": 7.22
    },
    {
      "dt": 1613715300,
      "sunrise": 1613695923,
      "sunset": 1613736706,
      "temp": {
        "day": 19.84,
        "min": 7.26,
        "max": 20.71,
        "night": 9.11,
        "eve": 14.66,
        "morn": 7.39
      },
      "feels_like": {
        "day": 16.26,
        "night": 6.09,
        "eve": 11.2,
        "morn": 4.16
      },
      "pressure": 1021,
      "humidity": 25,
      "dew_point": -2.61,
      "wind_speed": 2.12,
      "wind_deg": 151,
      "weather": [
        {
          "id": 800,
          "main": "Clear",
          "description": "clear sky",
          "icon": "01d"
        }
      ],
      "clouds": 0,
      "pop": 0.27,
      "uvi": 7.35
    },
    {
      "dt": 1613801700,
      "sunrise": 1613782271,
      "sunset": 1613823147,
      "temp": {
        "day": 20.94,
        "min": 7.68,
        "max": 21.28,
        "night": 9.45,
        "eve": 15.41,
        "morn": 7.68
      },
      "feels_like": {
        "day": 17.59,
        "night": 6.55,
        "eve": 12.06,
        "morn": 4.34
      },
      "pressure": 1020,
      "humidity": 23,
      "dew_point": -1.57,
      "wind_speed": 1.75,
      "wind_deg": 157,
      "weather": [
        {
          "id": 800,
          "main": "Clear",
          "description": "clear sky",
          "icon": "01d"
        }
      ],
      "clouds": 0,
      "pop": 0.23,
      "uvi": 7.84
    },
    {
      "dt": 1613888100,
      "sunrise": 1613868618,
      "sunset": 1613909587,
      "temp": {
        "day": 21.85,
        "min": 8.1,
        "max": 21.85,
        "night": 9.64,
        "eve": 15.55,
        "morn": 8.1
      },
      "feels_like": {
        "day": 18.97,
        "night": 6.79,
        "eve": 12.24,
        "morn": 5.01
      },
      "pressure": 1017,
      "humidity": 23,
      "dew_point": -0.17,
      "wind_speed": 1.24,
      "wind_deg": 207,
      "weather": [
        {
          "id": 800,
          "main": "Clear",
          "description": "clear sky",
          "icon": "01d"
        }
      ],
      "clouds": 0,
      "pop": 0.23,
      "uvi": 8.49
    },
    {
      "dt": 1613974500,
      "sunrise": 1613954964,
      "sunset": 1613996027,
      "temp": {
        "day": 21.83,
        "min": 8.41,
        "max": 21.94,
        "night": 10.01,
        "eve": 15.25,
        "morn": 8.41
      },
      "feels_like": {
        "day": 18.56,
        "night": 7.03,
        "eve": 11.85,
        "morn": 5.35
      },
      "pressure": 1015,
      "humidity": 23,
      "dew_point": 0.12,
      "wind_speed": 1.78,
      "wind_deg": 172,
      "weather": [
        {
          "id": 800,
          "main": "Clear",
          "description": "clear sky",
          "icon": "01d"
        }
      ],
      "clouds": 0,
      "pop": 0.04,
      "uvi": 9
    },
    {
      "dt": 1614060900,
      "sunrise": 1614041309,
      "sunset": 1614082467,
      "temp": {
        "day": 21.79,
        "min": 8.81,
        "max": 21.82,
        "night": 10.3,
        "eve": 15.73,
        "morn": 8.81
      },
      "feels_like": {
        "day": 18.21,
        "night": 7.45,
        "eve": 12.8,
        "morn": 5.98
      },
      "pressure": 1014,
      "humidity": 23,
      "dew_point": -0.4,
      "wind_speed": 2.22,
      "wind_deg": 171,
      "weather": [
        {
          "id": 800,
          "main": "Clear",
          "description": "clear sky",
          "icon": "01d"
        }
      ],
      "clouds": 0,
      "pop": 0.23,
      "uvi": 9
    },
    {
      "dt": 1614147300,
      "sunrise": 1614127653,
      "sunset": 1614168906,
      "temp": {
        "day": 22.02,
        "min": 9.01,
        "max": 22.36,
        "night": 11.07,
        "eve": 16.27,
        "morn": 9.01
      },
      "feels_like": {
        "day": 18.49,
        "night": 8.13,
        "eve": 13.66,
        "morn": 6.03
      },
      "pressure": 1011,
      "humidity": 23,
      "dew_point": -0.1,
      "wind_speed": 2.19,
      "wind_deg": 164,
      "weather": [
        {
          "id": 800,
          "main": "Clear",
          "description": "clear sky",
          "icon": "01d"
        }
      ],
      "clouds": 0,
      "pop": 0.22,
      "uvi": 9
    }
  ]
}

Leave a Reply