This is an example of public transport information system implemented on Maxbot framework. A passenger at the stop can find out what routes go through it and when the next bus, trolleybus or tram will arrive. To do this, passenger scanns the QR code at this stop, and goes to the bot, which gives him all the information. Each driver uses bot to choose the route and inform the service of current location.
The example consists of two bots and an external service:
DriverBot— bot for drivers,PassengerBot— bot for passengers,Server— external service.
- registers a driver by requesting a phone number,
- requests the current coordinates of the driver,
- displays a list of all routes ordered by driver distance,
- provides a choice of route to work,
- updates the driver’s coordinates using the
telegram live locationfunction, - starts/ends of the trip along the route.
- displays the list of routes passing through the stop, when you go to the chat using a QR code,
- searches the nearest driver on the selected route and displays the distance to him and the time to arrive at the stop.
- stores data about drivers in the database: phone number, location, selected route, status (active or inactive),
- stores data about stops and routes,
- searches for the nearest driver using the service openrouteservice.org.
Note Service does not verify that the driver:
- has left the route, his location is not on his route,
- does not send location for a long time, for example when the live-locations function expires.
Note The QRCodeGenerator is used to generate QR code images.
- it creates QR codes with deeplink,
- this images are attached at the stops, each stop has its own QR code,
- passenger puts the phone camera on the QR code, goes to the passenger bot that informs what routes passes through this stop,
- passenger selects the route, then bot informs him when the nearest driver will arrive.
Before you start, you should make sure that the system has:
- Python 3.9 - 3.11,
- Git,
- Poetry,
- Pagekite,
We recommend to just download pagekite.py and use it as a separate scenario.
curl -O https://pagekite.net/pk/pagekite.py
It's also required:
- To register and receive a token for the Routing Service,
- To create two bots in
Telegram: driver’s chat and passenger's chat: see BotFather and instruction.
Note You'll need a smartphone with Telegram apps to work properly with DriverBot. Desktop versions of Telegram do not fit, as they don't allow you to send the location.
Clone this repository and change current directory
git clone https://github.com/maxbot-ai/transport_bot
cd transport_botInstall the package with dependencies
poetry shell
poetry install- Route settings are stored in a JSON file, an example is in
tests/routes.json. - Settings for
Serverare stored in the file./transport_bot.conf. - Environment settings are stored in the file
.env.
{
"stops": {
"<stop_key:string>": {
"name": "<string>",
"address": "<string>",
"location": {
"lat": "<float>",
"lon": "<float>"
}
},
...
},
"routes": {
"<route_key:string>": {
"name": "<string>",
"type": "<enum[bus, tram, trolleybus]>",
"stops": [
"<stop_key_1:string>",
"<stop_key_2:string>",
....
]
},
...
}
}To configure the service, save the file transport_bot.conf.template with the name transport_bot.conf. Open the transport_bot.conf file in your favorite editor and set the actual values for all parameters:
routes_json— path to a local JSON file with a list of routes and stops,bind_port— port to start theServer,ors_token— token to access the openrouteservice.org service.
To configure bots, save the file env.template with the name .env in the transport_bot directory. Open the .env file in your favorite editor and set the actual values for all parameters:
TELEGRAM_DRIVER_API_KEY— the token ofTelegrambot, that will becomeDriverBot.TELEGRAM_PASSENGER_API_KEY— the token ofTelegrambot, that will becomePassengerBot.TRANSPORT_BOT_API— address of theServer. Leavehttp://localhost:5000, if everything runs on one machine.
-
Run qrcode_generator tool:
poetry run qrcode_generator --passenger-bot-name=<BOT_NAME> --routes-data-json=<ROUTE>where BOT_NAME is username for your Telegram bot. It must end with
bot, e.g. mytransport_bot. ROUTE is the path to the routes file. For example,poetry run qrcode_generator --passenger-bot-name=mytransport_bot --routes-data-json=tests/routes.jsonAfter launching, all QR codes of stops are saved in the
transport_bot/qr_codesfolder. -
Run
Server:poetry run server --config transport_bot.conf -
Run
DriverBot:-
We will use pagekite to get an external address and create a tunnel. You can use any other similar utility, such as ngrok or setup communication through
reverse-proxy. -
If you use pagekite, you need to register and specify the subdomain to be used to create the tunnel. For example,
driverbot.pagekite.me. -
Select the port for
DriverBot, for example,5011 -
Run
pagekite. Set the port and the external address. For example,python3 pagekite.py 5011 driverbot.pagekite.me -
Make sure that
pagekitehas started successfully and created a tunnel -
Make sure you are in the
transport_botdirectory -
Run the bot with the command
poetry run maxbot run --bot transport_bot.bot:driver --updater=webhooks --host=localhost --port=<BIND_PORT> --public-url=<DRIVER_BOT_PUBLIC_URL>In our particular example:
poetry run maxbot run --bot transport_bot.bot:driver --updater=webhooks --host=localhost --port=5011 --public-url=https://driverbot.pagekite.me
-
-
Run
PassengerBot:- In the pagekite control panel, add the
kiteto create another tunnel. For example,passengerbot.pagekite.me. To do this, click theadd kitebutton - Select the port for
PassengerBot, for example,5012 - Run
pagekite. Set the port and the external address. For example,python3 pagekite.py 5012 passengerbot.pagekite.me - Make sure that
pagekitehas started successfully and created a tunnel - Make sure you are in the
transport_botdirectory - Run the bot with the command
In our particular example:
poetry run maxbot run --bot transport_bot.bot:passenger --updater=webhooks --host=localhost --port=<BIND_PORT> --public-url=<PASSENGER_BOT_PUBLIC_URL>poetry run maxbot run --bot transport_bot.bot:passenger --updater=webhooks --host=localhost --port=5012 --public-url=https://passengerbot.pagekite.me
- In the pagekite control panel, add the
After successfully launching Server, DriverBot and PassengerBot you can test the example.
- Text
DriverBotviaTelegramand follow the hint. Send the geo-position and start the route. - Open the QR code and scan it through the phone camera. After you go to the chat, click on the route you are interested in.
- If the route started by the driver is the same as the selected one, information about the driver and distance to him will be displayed.
- To test multiple routes and multiple drivers at the same time, you can run the virtual drivers script, see below.
Note For Telegram on iOS it is necessary to scan the QR code when the application is closed or another dialog is open (not with the PassengerBot), otherwise the stop will not change.
There is a script to create and run virtual drivers: transport_bot/virtual_drivers.py. Virtual drivers are drivers that are created in Server database, but they have no real Telegram clients. The script starts their movement, sends their location on the route after a certain period of time. The movement points are specified inside the script. The script saves the map with stops(small dots in brown color) and locations of these virtual drivers in folder ./virtual_drivers.
To create two virtual drivers per route run command:
poetry run virtual_drivers --config transport_bot.conf
- Route 9 with drivers Red and Black — from Trafalgar Square, along the south side of the Hyde Park,
- Route 23 with drivers Blue and Purple — along the east side of the Hyde Park to Trafalgar Square,
- Route 13 with drivers Green and Yellow — from Regent's Park, along the east side of the Hyde Park to Buckingham Palace,
The script also allows you to track the position of virtual drivers on the map. It can save the map with the positions of the drivers at each step of its execution (if virtual_mode option is set to all). The map images will be in the virtual_drivers directory.
If virtual_mode is one (default), the script will save the map with the drivers' positions only on the last step.
Open the transport_bot.conf file in your favorite editor and set the actual values for the parameters:
virtual_count— the number of steps. Step is a small advance on the routes.virtual_mode— mode of virtual drivers. Valuesoneorall.virtual_timeout— pause between steps in seconds, can be equal to 0.
This example shows the implementation details of the following features:
- using an external
HTTPservice, - database schema,
- adding new commands to channels using
mixin, - generation of QR codes,
- running tests,
- adding dependencies.
- An external
HTTPservice in python is used to implementServerbusiness logic. - Implementation can be found in the
transport_bot/server.pyfile and thetransport_bot/api_servicefolder. - It is accessed from bots via external
HTTPcallsREST.
Example:
response: |-
{% PUT "transport_service://driver/{}/location".format(dialog.user_id) body {
'latitude': slots.location.latitude,
'longitude': slots.location.longitude
}
%}The database consists of one table for storing information about drivers:
- name
- phone
- chosen route
- current coordinates
- date of last coordinates update
Note Routes and stops data are stored in a JSON file, see "The format of the JSON file with routes".
mixinis used to add features to communicate withTelegrammessenger,- the
channelsfolder contains the implementation of additional features of channels.
Telegramdocumentation
Example of usage in scenario:
- condition: message.contact
response: |-
- text: phone={{message.contact.phone_number}}
- text: phone={{message.contact.first_name}}Telegramdocumentation- The
request_contactparameter is used in implementation forTelegram
Example of using in bot scenario:
response: |-
- keyboard_button_contact:
title: "Send your phone"
text: "Could you please send me your contact."Telegramdocumentation- You can enable the function of periodically sending a location
https://telegram.org/blog/live-locations, then thelive_periodparameter will be added to the location message - There is no special button to enable live-locations
- You can send an arbitrary location for testing
Example of using in bot scenario:
- condition: message.location
response: |-
- text: latitude={{message.location.latitude}}
- text: longitude={{message.location.longitude}}
- text: live_period={{message.location.live_period}}Note Sending a location and the function live location work only on phones, the desktop application does not have this functionality.
Telegramdocumentation- The
request_locationparameter is used in implementation forTelegram
Example of using in bot scenario:
response: |-
- keyboard_button_location:
text: "Enter your location."
title: "My location"Telegramdocumentation- Used to start/stop work and change the route
Example of using in bot scenario:
response: |-
- keyboard_button_list:
text: "Click to start or change the route:"
buttons:
- start route
- change routeInlineKeyboardMixindocumentationCallbackQueryMixindocumentation — the format of the response when inline buttons are pressed- Used when displaying the list of routes: each route is a button with the name of the route
Example of using in bot scenario:
response: |-
- inline_keyboard:
text: Please choose a route
rows:
- row:
- button:
caption: Button name №1
callback_data: button_data1
- button:
caption: Button name №2
callback_data: button_data2
- row:
- button:
caption: Button name №3
callback_data: button_data3
- button:
caption: Button name №3
callback_data: button_data3Example of inline-button handling:
- condition: message.callback_query
label: route
response: |-
- text: {{ message.callback_query.data }}To generate QR code images, the QRCodeGenerator is used.
- It creates QR codes with a deeplink in the format
https://t.me/{passenger_bot_name}?start={stop_key}, - You can find the script in the
transport_bot/qrcode.pyfile, - This images are attached at the stops, each stop has its own QR code,
- When you put the phone camera on the QR code you will go to the passenger bot with the parameter
stop_key— the current stop with the list of routes going through this stop, - When passenger selects the route bot informs him when the nearest driver will arrive.
- Command to start:
poetry run qrcode_generator --passenger-bot-name=<BOT_NAME> --routes-data-json=<ROUTE>
poetry shell
poetry install (if not previously installed)
(poetry run) pytest tests/The external python service contains a number of dependencies that need to be installed.
To do this, add these dependencies to the pyproject.toml file:
[tool.poetry.dependencies]
python = ">=3.9, <3.12"
maxbot = "^0.2.0b2"
click-config-file = {version = "^0.6.0"}
Flask-SQLAlchemy = {version = "^3.0.2"}
...
The maxbot dependency should be in all examples.
The tool.poetry.group.dev.dependencies section lists dependencies to run unit tests ,
in this example it is:
[tool.poetry.group.dev.dependencies]
pytest = "^7.2.0" (for pytest based unit tests)
httpretty = "^1.1.4" (mock library for `HTTP` modules)