Introduction
We've all been there - sitting at the office, wondering "Should I leave now or wait a bit longer?" Traffic apps tell you the current conditions, but they don't tell you when to leave. What if you could have a personal assistant that monitors traffic for you and sends you a notification at exactly the right moment, telling you the best route home?
Even better - what if you need to pick up groceries or stop at the gym on your way home? Traditional route planners make you manually add stops every time. But with a smart system, you could simply send a message like "Add Whole Foods" and your assistant would recalculate the optimal departure time for your multi-stop journey.
In this article, I'll show you how to build exactly that - a smart commute assistant using Python, Google Maps API, and Telegram Bot. By the end, you'll have a system that:
- Monitors traffic automatically at your specified time
- Calculates when you should leave based on real-time conditions
- Sends you Telegram notifications with the best route home
- Supports dynamic waypoints - add stops on the fly via chat
- Adapts to traffic - alerts you earlier when there's congestion
- Runs 24/7 on a Raspberry Pi or cloud server
Why This Matters
The Problem: Most of us leave work at a fixed time, regardless of traffic. This means we either leave too early (wasting time at the office) or too late (sitting in traffic). And when we need to make stops, we're constantly checking our phone to see if we have time.
The Solution: A proactive system that:
- Checks traffic conditions at your desired time
- Calculates the optimal departure time
- Notifies you when it's time to leave
- Lets you add stops dynamically
- Adjusts timing based on traffic patterns
Real-world impact:
- Save 15-30 minutes daily by leaving at the optimal time
- Reduce stress from traffic uncertainty
- Never forget important stops on the way home
- Better work-life balance with predictable commute times
Architecture Overview
Before diving into code, let's understand the system architecture:
┌─────────────────────────────────────────────────────────┐
│ USER (You at work) │
│ │
│ "Add gym on my way home" │
│ ↓ │
│ [Telegram App] ←→ [Telegram Bot API] │
└────────────────────┬────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────┐
│ YOUR SERVER (Python Application) │
│ │
│ ┌───────────────────┐ ┌──────────────────┐ │
│ │ Schedule Manager │ │ Command Handler │ │
│ │ - Check at 5 PM │ │ - Parse messages│ │
│ │ - Every 5 min │ │ - Add waypoints │ │
│ └────────┬──────────┘ └────────┬─────────┘ │
│ │ │ │
│ ↓ ↓ │
│ ┌──────────────────────────────────────────┐ │
│ │ Traffic Analyzer │ │
│ │ - Query Google Maps API │ │
│ │ - Calculate optimal route │ │
│ │ - Determine departure time │ │
│ └────────────────┬─────────────────────────┘ │
│ │ │
│ ↓ │
│ ┌────────────────────────────────┐ │
│ │ Notification Engine │ │
│ │ - Send Telegram message │ │
│ │ - Include route info │ │
│ │ - Show waypoints │ │
│ └────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ EXTERNAL SERVICES │
│ │
│ [Google Maps API] [Telegram Bot API] │
│ - Traffic data - Message delivery │
│ - Route calculation - Command processing │
└─────────────────────────────────────────────────────────┘
Prerequisites
What You'll Need
1. Python Environment
- Python 3.8 or higher
- Basic knowledge of Python and async programming
2. API Credentials (Both Free!)
-
Google Maps API Key: For traffic data and routing
- Free tier: $200/month credit (≈40,000 requests)
- Your usage: ~600 requests/month
- Cost: $0/month
-
Telegram Bot Token: For notifications
- Completely free, no limits for personal use
- Cost: $0/month
3. Hosting (Optional)
- Your computer (free)
- Raspberry Pi ($35 one-time)
- Cloud VPS like DigitalOcean ($5/month)
Getting Your API Keys
Google Maps API (5 minutes)
- Go to Google Cloud Console
- Create a new project or select existing
- Enable these APIs:
- Directions API
- Distance Matrix API (optional, for multi-stop optimization)
- Create credentials → API Key
-
Important: Restrict your API key:
- Go to API Key settings
- Add API restrictions: Only allow Directions API
- Save your key securely
Telegram Bot (2 minutes)
- Open Telegram and search for
@BotFather - Send
/newbotcommand - Follow prompts to name your bot (e.g., "My Commute Assistant")
- Save the bot token (looks like:
123456789:ABCdefGHIjklMNOpqrsTUVwxyz) - Get your Chat ID:
- Send a message to your bot
- Visit:
https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates - Find your
chat_idin the JSON response
Pro tip: Save both tokens immediately to a password manager!
Building the System
Project Setup
Let's start by setting up our project structure:
# Create project directory
mkdir smart-commute
cd smart-commute
# Create virtual environment
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install requests python-telegram-bot schedule python-dotenv
Create a .env file for your secrets:
# .env
GOOGLE_MAPS_API_KEY=your_google_maps_api_key_here
TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here
TELEGRAM_CHAT_ID=your_telegram_chat_id_here
# Your locations
WORK_ADDRESS=456 Work Avenue, Your City, ST 12345
HOME_ADDRESS=123 Home Street, Your City, ST 12345
# Schedule settings
CHECK_TIME=17:00
DESIRED_ARRIVAL_TIME=18:00
BUFFER_MINUTES=10
Core Implementation
Now let's build the system. I'll break it down into logical components:
1. Configuration Manager
# config.py
import os
from dataclasses import dataclass, field
from typing import List, Optional
from dotenv import load_dotenv
load_dotenv()
@dataclass
class CommuteConfig:
"""Configuration for commute monitoring"""
work_address: str
home_address: str
check_time: str # HH:MM format
desired_arrival_time: str # HH:MM format
buffer_minutes: int = 10
heavy_traffic_threshold: float = 1.3
waypoints: List[str] = field(default_factory=list)
@classmethod
def from_env(cls):
"""Load configuration from environment variables"""
return cls(
work_address=os.getenv('WORK_ADDRESS'),
home_address=os.getenv('HOME_ADDRESS'),
check_time=os.getenv('CHECK_TIME', '17:00'),
desired_arrival_time=os.getenv('DESIRED_ARRIVAL_TIME', '18:00'),
buffer_minutes=int(os.getenv('BUFFER_MINUTES', '10')),
heavy_traffic_threshold=float(os.getenv('TRAFFIC_THRESHOLD', '1.3'))
)
def add_waypoint(self, address: str):
"""Add a stop on the way home"""
if address not in self.waypoints:
self.waypoints.append(address)
return True
return False
def remove_waypoint(self, address: str):
"""Remove a stop"""
if address in self.waypoints:
self.waypoints.remove(address)
return True
return False
def clear_waypoints(self):
"""Clear all waypoints"""
self.waypoints.clear()
def get_full_route(self) -> List[str]:
"""Get complete route: work → waypoints → home"""
return [self.work_address] + self.waypoints + [self.home_address]
Key features:
- Loads configuration from environment variables (secure!)
- Dynamic waypoint management
- Returns the full route including all stops
2. Traffic Monitor
# traffic_monitor.py
import requests
from typing import Dict, List, Optional, Tuple
from datetime import datetime, timedelta
class TrafficMonitor:
"""Handles traffic data retrieval and route analysis"""
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://maps.googleapis.com/maps/api/directions/json"
def get_route_with_traffic(self,
origin: str,
destination: str,
waypoints: Optional[List[str]] = None) -> Optional[Dict]:
"""
Get route information with traffic data
Args:
origin: Starting location
destination: Final destination
waypoints: Optional list of stops along the way
Returns:
Dictionary with route and traffic information
"""
params = {
'origin': origin,
'destination': destination,
'departure_time': 'now',
'traffic_model': 'best_guess',
'key': self.api_key
}
# Add waypoints if provided
if waypoints:
params['waypoints'] = 'optimize:false|' + '|'.join(waypoints)
try:
response = requests.get(self.base_url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
if data['status'] == 'OK':
return self._parse_route_data(data, waypoints)
else:
print(f"❌ API Error: {data['status']} - {data.get('error_message', '')}")
return None
except requests.exceptions.RequestException as e:
print(f"❌ Request failed: {e}")
return None
def _parse_route_data(self, data: Dict, waypoints: Optional[List[str]]) -> Dict:
"""Parse Google Maps API response"""
route = data['routes'][0]
legs = route['legs']
# Calculate total duration and distance
total_duration = sum(leg['duration']['value'] for leg in legs)
total_duration_traffic = sum(
leg.get('duration_in_traffic', leg['duration'])['value']
for leg in legs
)
total_distance = sum(leg['distance']['value'] for leg in legs)
# Parse waypoint information
stops = []
if waypoints:
for i, leg in enumerate(legs[:-1]): # All legs except the last
stops.append({
'address': waypoints[i] if i < len(waypoints) else 'Unknown',
'duration_to_next': leg['duration']['value'],
'distance_to_next': leg['distance']['value']
})
return {
'total_duration': total_duration,
'total_duration_traffic': total_duration_traffic,
'total_distance': total_distance,
'distance_text': self._meters_to_text(total_distance),
'summary': route['summary'],
'waypoints': stops,
'start_address': legs[0]['start_address'],
'end_address': legs[-1]['end_address'],
'traffic_ratio': total_duration_traffic / total_duration
}
def _meters_to_text(self, meters: int) -> str:
"""Convert meters to readable text"""
if meters < 1000:
return f"{meters} m"
else:
km = meters / 1000
return f"{km:.1f} km"
def calculate_departure_time(self,
traffic_data: Dict,
arrival_time: str,
buffer_minutes: int) -> Tuple[datetime, int]:
"""
Calculate when to leave based on traffic
Returns:
Tuple of (departure_time, travel_minutes)
"""
# Parse desired arrival time
arrival_hour, arrival_minute = map(int, arrival_time.split(':'))
today = datetime.now().replace(
hour=arrival_hour,
minute=arrival_minute,
second=0,
microsecond=0
)
# If arrival time has passed today, use tomorrow
if today < datetime.now():
today += timedelta(days=1)
# Calculate travel time with buffer
travel_seconds = traffic_data['total_duration_traffic']
travel_minutes = (travel_seconds / 60) + buffer_minutes
# Calculate departure time
departure_time = today - timedelta(minutes=travel_minutes)
return departure_time, int(travel_minutes)
def analyze_traffic(self, traffic_data: Dict, threshold: float) -> str:
"""
Analyze traffic conditions
Returns:
Traffic status emoji and text
"""
ratio = traffic_data['traffic_ratio']
if ratio >= threshold:
return "🔴 Heavy traffic"
elif ratio >= 1.1:
return "🟡 Moderate traffic"
else:
return "🟢 Light traffic"
Key features:
- Multi-stop route calculation
- Real-time traffic analysis
- Automatic departure time calculation
- Traffic condition classification
Top comments (0)