Building a Telegram bot with IBM Cloud Functions

Building a Telegram bot with IBM Cloud Functions

The Useless Idea Behind It:

Me and my two roommates live in an apartment where we have a cook who comes in daily to prepare delicious meals for us. All is well and good until he comes in asks 'What to make for dinner?' . All of us dread this question because it requires checking the pantry and finding out what is available and consulting among us what to have for dinner.Leaving out the 'I don't wanna have eggs today, I had it in the morning' type shenanigans. What can we do to make our lives simpler with a bit of tech?

The Trivial Solution:

Set up a Google calendar and add our cook to it. We schedule our meals taking into account everyone's preferences. Calendar would send him a notification and he would know. Simple right? But lets add some more tech to it.

Annotation 2020-03-04 2225556.png

The Dev way to do it:

Recently I got a Free IBM cloud account and wanted to try IBM Cloud Functions. Another useless idea incoming: Let's make a serverless app which picks up events(containing the menu for the day) from Google Calendar and daily send it to a Telegram group consisting of me, my roommates and the cook.

Steps to achieve this:

First you have a create a free tier account in cloud.ibm.com and follow these steps to setup your ibmcloud cli

Cloud Functions should be containerized and the implementation should do one simple job, the more time and resources you save for each job the more free requests per month you get. More on planning here

For this particular project we need a action that can be invoked from a URL. More on actions

I am using python-3.7 environment for this and a couple of Google api client packages.

pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

Create a directory with your project name

mkdir cook_ko_bolde && cd cook_ko_bolde
virtualenv virtualenv

Make sure you name you virtualenv as virtualenv. We will come to this later. Create a file called main.py and helper,py in the same directory.

#__main__.py
from helper import helper
def main(args):
    return helper(args)
#__helper__.py
from urllib.request import urlopen
from urllib.parse import urlencode
import datetime
import httplib2
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials


def get_google_calendar_service():
    credentials = ServiceAccountCredentials.from_json_keyfile_name(
        filename='./creds.json',
        scopes=['https://www.googleapis.com/auth/calendar']
    )
    http = credentials.authorize(httplib2.Http())

    service = build('calendar', 'v3', http=http)

    return service


def get_events():
    service = get_google_calendar_service()
    now = datetime.datetime.utcnow().isoformat() + 'Z'
    events_result = service.events().list(calendarId='YOUR_CALENDAR_ID',
                                          timeMin=now, maxResults=1, singleEvents=True, orderBy='startTime').execute()
    events = events_result.get('items', [])
    event = events[0]
    if not event:
        return {'text': 'No food for today! Happy dieting'}
    text = 'Menu for today \nMenu : {} \nItems: {}'.format(event['summary'], event['description'])
    return {'text': text}


def helper(data):
    text = get_events()['text']
    api_key = data['TGRAM_API_KEY']
    chat_id = data['TGRAM_CHAT_ID']
    message = {
        'chat_id': '-' + chat_id,
        'text': text
    }
    url_text = urlencode(message)
    url = 'https://api.telegram.org/' \
          'bot{}/sendMessage?{}'.format(api_key, url_text)
    f = urlopen(url)
    return {
        'message': f.read().decode('utf-8')
    }

How to get Google API Service Account Credentials

Add your downloaded creds.json file to the same directory. Follow this How to create a Telegram bot, and send messages with Python to get your TGRAM_API_KEY & TGRAM_CHAT_ID

To get your YOUR_CALENDAR_ID go Settings and search for your calendar. Copy the Calendar ID as here

j-M2OtCgW.png

Now that we done with the code, lets deploy. Create a zip file containing your project files and virtualenv directory as well. Make sure the name of the directory is virtualenv otherwise ibmcloud cli will not be able to detect it while build the image .

cd cook_ko_bolde
zip -r target.zip __main__.py helper.py virtualenv creds.json

Lets create the action with parameters.

ibmcloud fn action create cook_ko_bolde --kind python:3 target.zip --param TGRAM_API_KEY <your-tgram-api-key> TGRAM_CHAT_ID <your-tgram-chat/group-id>

Login in to cloud.ibm.com and head over to Cloud Function. You should be seeing something like this.

Annotation 2020-03-04 220823.png

Head over and click on Invoke . If you have no errors you should have received a message from your Telegram Bot telling you the contents of today's meal.

telegram bot

But we don't wanna invoke manually every time do we? We need to get an HTTP API endpoint which invokes the action. Head over to Endpoints and tick off Enable as Web Action optionally you can also enable Raw HTTP handling .

Annotation 2020-03-04 221705.png

Copy the URL and open it in a browser. If everything is proper you should get the similar message from your Telegram Bot as before.

But someone has to hit the URL in order for it to work. Lets try scheduling this using Web based Cron scheduler.

Head over to Easy Cron and get a free account. Create a new Cron Job and add the copied URL to the URL to call field, change the interval as you like it.

Annotation 2020-03-04 222555.png

That's it , we did it. We managed to create a serverless app to notify our cook of our daily menu. An 'useless idea' but nonetheless great fun to make.

P.S - cook_ko_bolde means Tell the cook in Hindi