DEV Community

Alex Spinov
Alex Spinov

Posted on

I Built a Morning Briefing Bot in 50 Lines of Python (Weather + Crypto + News)

Every morning I used to open 5 tabs: weather, news, crypto prices, calendar, and email. That's 10 minutes of scattered attention before I even start working.

So I built a bot that sends me everything in one Telegram message at 7 AM. Here's the entire thing.

The Stack

  • Python 3.10+ (no external frameworks)
  • Open-Meteo API — weather (free, no key)
  • CoinGecko API — crypto prices (free, no key)
  • NewsAPI — headlines (free tier, key required)
  • Telegram Bot API — delivery

Total cost: $0/month. Runs on any machine with cron.

Step 1: Weather (Open-Meteo)

No API key. No signup. Just works.

\`python
import requests
from datetime import datetime

def get_weather(lat=55.75, lon=37.62): # Moscow
"""Get current weather + today's forecast"""
r = requests.get('https://api.open-meteo.com/v1/forecast', params={
'latitude': lat, 'longitude': lon,
'current_weather': True,
'daily': 'temperature_2m_max,temperature_2m_min,precipitation_sum',
'timezone': 'auto', 'forecast_days': 1
}).json()

cw = r['current_weather']
daily = r['daily']

return (
    f"🌡 Weather: {cw['temperature']}°C "
    f"(high {daily['temperature_2m_max'][0]}°, low {daily['temperature_2m_min'][0]}°)\n"
    f"💧 Rain: {daily['precipitation_sum'][0]}mm"
)
Enter fullscreen mode Exit fullscreen mode

`\

Step 2: Crypto Prices (CoinGecko)

Also free, also no key needed.

\`python
def get_crypto():
"""Get top 3 crypto prices with 24h change"""
r = requests.get('https://api.coingecko.com/api/v3/simple/price', params={
'ids': 'bitcoin,ethereum,solana',
'vs_currencies': 'usd',
'include_24hr_change': True
}).json()

lines = []
symbols = {'bitcoin': 'BTC', 'ethereum': 'ETH', 'solana': 'SOL'}
for coin, sym in symbols.items():
    price = r[coin]['usd']
    change = r[coin]['usd_24h_change']
    arrow = '📈' if change > 0 else '📉'
    lines.append(f"{arrow} {sym}: ${price:,.0f} ({change:+.1f}%)")

return '\n'.join(lines)
Enter fullscreen mode Exit fullscreen mode

`\

Step 3: News Headlines (NewsAPI)

Free tier gives you 100 requests/day — more than enough for a daily bot.

\`python
def get_news(api_key, country='us', count=5):
"""Get top headlines"""
r = requests.get('https://newsapi.org/v2/top-headlines', params={
'country': country, 'pageSize': count, 'apiKey': api_key
}).json()

lines = []
for i, article in enumerate(r.get('articles', [])[:count], 1):
    lines.append(f"{i}. {article['title']}")

return '📰 Headlines:\n' + '\n'.join(lines)
Enter fullscreen mode Exit fullscreen mode

`\

Step 4: Telegram Delivery

\python
def send_telegram(bot_token, chat_id, text):
"""Send message via Telegram"""
requests.post(
f'https://api.telegram.org/bot{bot_token}/sendMessage',
json={'chat_id': chat_id, 'text': text, 'parse_mode': 'HTML'}
)
\
\

Putting It All Together

\`python

!/usr/bin/env python3

"""Morning briefing bot — runs daily via cron"""

import requests
from datetime import datetime

=== CONFIG ===

TELEGRAM_TOKEN = 'your-bot-token'
TELEGRAM_CHAT_ID = 'your-chat-id'
NEWS_API_KEY = 'your-newsapi-key'
LAT, LON = 40.71, -74.01 # New York

def get_weather():
r = requests.get('https://api.open-meteo.com/v1/forecast', params={
'latitude': LAT, 'longitude': LON, 'current_weather': True,
'daily': 'temperature_2m_max,temperature_2m_min,precipitation_sum',
'timezone': 'auto', 'forecast_days': 1
}).json()
cw = r['current_weather']
d = r['daily']
return f"🌡 {cw['temperature']}°C (↑{d['temperature_2m_max'][0]}° ↓{d['temperature_2m_min'][0]}°) 💧{d['precipitation_sum'][0]}mm"

def get_crypto():
r = requests.get('https://api.coingecko.com/api/v3/simple/price', params={
'ids': 'bitcoin,ethereum,solana', 'vs_currencies': 'usd', 'include_24hr_change': True
}).json()
lines = []
for coin, sym in [('bitcoin','BTC'),('ethereum','ETH'),('solana','SOL')]:
p, c = r[coin]['usd'], r[coin]['usd_24h_change']
lines.append(f"{'📈' if c>0 else '📉'} {sym}: ${p:,.0f} ({c:+.1f}%)")
return '\n'.join(lines)

def get_news():
r = requests.get('https://newsapi.org/v2/top-headlines', params={
'country': 'us', 'pageSize': 5, 'apiKey': NEWS_API_KEY
}).json()
return '📰 ' + '\n'.join(f"{i}. {a['title']}" for i,a in enumerate(r.get('articles',[])[:5],1))

def main():
msg = f"☀️ Morning Briefing — {datetime.now().strftime('%B %d, %Y')}\n\n"
msg += get_weather() + '\n\n'
msg += get_crypto() + '\n\n'
msg += get_news()

requests.post(f'https://api.telegram.org/bot{TELEGRAM_TOKEN}/sendMessage',
              json={'chat_id': TELEGRAM_CHAT_ID, 'text': msg, 'parse_mode': 'HTML'})
print('Briefing sent!')
Enter fullscreen mode Exit fullscreen mode

if name == 'main':
main()
`\

That's ~50 lines of actual logic. Save it, add a cron job, done.

Setting Up Cron

\`bash

Run every day at 7:00 AM

crontab -e
0 7 * * * /usr/bin/python3 /path/to/briefing.py
`\

Extending It

I've added more modules over time:

  • Calendar — Google Calendar API shows today's events
  • GitHub — shows overnight stars/issues on my repos
  • Exchange rates — USD/EUR/GBP via exchangerate.host

Each module is just a function that returns a string. The architecture stays dead simple.

What I Learned

  1. Free APIs are incredibly powerful — most developers underuse them
  2. Telegram bots are the simplest delivery mechanism — beats building a UI
  3. Cron + Python + free APIs = infinite possibilities with zero infrastructure cost
  4. Start with 3 data sources, not 10 — you can always add more

For a list of 300+ free APIs to build your own version, check out my curated API directory.


What would you add to your morning briefing? I'm curious what data other developers check first thing.

Follow for more Python automation tutorials.

Top comments (0)