Skip to content

Instantly share code, notes, and snippets.

@azer
Created February 2, 2026 14:29
Show Gist options
  • Select an option

  • Save azer/5d8220b4dff27b89fa08acd884761916 to your computer and use it in GitHub Desktop.

Select an option

Save azer/5d8220b4dff27b89fa08acd884761916 to your computer and use it in GitHub Desktop.
Automate BMS school lunch orders
0 9 * * 6 cd /home/fuji/dev/lunch/run.sh
"""
School Lunch Ordering Script using browser-use
==============================================
This script:
1. Logs into the school lunch website
2. CHECKS if meals are already ordered for next 2 weeks
3. Only orders if needed
4. Sends Telegram notification with status
Install dependencies:
pip install browser-use python-dotenv aiohttp
"""
import asyncio
import os
from datetime import datetime
from dotenv import load_dotenv
load_dotenv()
# ============================================
# CONFIGURATION
# ============================================
CUSTOMER_ID = os.getenv("LUNCH_CUSTOMER_ID", "")
PASSWORD = os.getenv("LUNCH_PASSWORD", "")
TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN", "")
TELEGRAM_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID", "")
LOGIN_URL = "https://widynski-roick.mbs5online.de/ordering/"
DIET_PREFERENCES = """
Diet rules for selecting lunch:
1. NEVER select any dish containing pork (Schwein, Schweinefleisch, Schinken, Speck, Bacon, Wurst unless specified as chicken/beef)
2. PREFER simple dishes like:
- Pasta dishes (Nudeln, Spaghetti, Penne, Makkaroni)
- Rice dishes (Reis)
- Chicken (Hähnchen, Huhn, Geflügel)
- Fish sticks (Fischstäbchen)
- Pizza
- Schnitzel (only if chicken/turkey, NOT pork)
- Pancakes (Pfannkuchen, Eierkuchen)
3. AVOID dishes with too many vegetables as main component
4. If multiple options available, choose the simpler/kid-friendlier option
5. German menu items are common - translate and apply rules accordingly
"""
# ============================================
# TELEGRAM NOTIFICATION
# ============================================
async def send_telegram_notification(message: str):
"""Send notification via Telegram"""
if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
print("Telegram not configured, skipping notification")
return False
import aiohttp
url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
payload = {
"chat_id": TELEGRAM_CHAT_ID,
"text": message,
"parse_mode": "HTML"
}
try:
async with aiohttp.ClientSession() as session:
async with session.post(url, json=payload) as response:
if response.status == 200:
print("✅ Telegram notification sent!")
return True
else:
print(f"❌ Telegram error: {response.status}")
return False
except Exception as e:
print(f"❌ Telegram error: {e}")
return False
# ============================================
# MAIN AGENT TASK
# ============================================
async def order_school_lunch():
"""Main function to order school lunch using browser-use"""
from browser_use import Agent, Browser, ChatBrowserUse
llm = ChatBrowserUse()
print("Using ChatBrowserUse LLM")
browser = Browser(use_cloud=True)
print("Using Browser-Use Cloud browser")
# Task now includes checking existing orders first
task = f"""
Your task is to check and order school lunch for Fuji for the next two weeks.
STEP 1 - LOGIN:
1. Go to: {LOGIN_URL}
2. Find the login form
3. Enter customer number/ID: {CUSTOMER_ID}
4. Enter password: {PASSWORD}
5. Click login/submit button
STEP 2 - CHECK EXISTING ORDERS:
1. After login, navigate to the ordering/menu section
2. Look at the next two weeks
3. CHECK if meals are ALREADY ORDERED for each day
4. Note which days already have orders and what meals are selected
5. Note which days are MISSING orders (need to be ordered)
STEP 3 - DETERMINE ACTION:
- If ALL days for the next 2 weeks already have meals ordered:
→ Report "All meals already ordered" with the list of what's ordered
→ Skip to STEP 5 (do not order anything)
- If SOME days are missing orders:
→ Report which days are already ordered
→ Proceed to STEP 4 to order the missing days
STEP 4 - SELECT MEALS (only for days without orders):
For each day that NEEDS ordering, select a meal following these diet rules:
{DIET_PREFERENCES}
After selecting, confirm/submit the order.
STEP 5 - FINAL REPORT:
Provide a clear summary with:
STATUS: [ALREADY_ORDERED / NEWLY_ORDERED / PARTIAL_ORDER]
ALREADY ORDERED (were already in the system):
- List each date and meal that was already ordered
NEWLY ORDERED (ordered during this session):
- List each date and meal that was just ordered
- Or "None" if everything was already ordered
DAYS WITHOUT ORDERS:
- List any days that couldn't be ordered (if any)
- Or "None" if all days are covered
IMPORTANT:
- Be thorough when checking existing orders
- Do NOT re-order days that already have meals selected
- If unsure about a dish containing pork, skip it
"""
agent = Agent(
task=task,
llm=llm,
browser=browser,
)
print("=" * 60)
print("🍽️ Starting School Lunch Ordering Agent")
print("=" * 60)
print("\nStep 1: Check existing orders")
print("Step 2: Order only if needed\n")
try:
history = await agent.run(max_steps=100)
result = history.final_result() if history.final_result() else "Task completed"
print("\n" + "=" * 60)
print("📋 RESULT")
print("=" * 60)
print(result)
# Determine status for Telegram
result_lower = str(result).lower()
if "already ordered" in result_lower or "already_ordered" in result_lower:
status_emoji = "✅"
status_text = "Already Ordered"
elif "newly ordered" in result_lower or "newly_ordered" in result_lower:
status_emoji = "🆕"
status_text = "New Orders Placed"
else:
status_emoji = "📋"
status_text = "Completed"
notification_message = f"""
🍽️ <b>School Lunch Order Check</b>
Child: Fuji
Status: {status_emoji} {status_text}
<b>Details:</b>
{str(result)[:800]}
<i>Checked at: {datetime.now().strftime('%Y-%m-%d %H:%M')}</i>
"""
await send_telegram_notification(notification_message)
return result
except Exception as e:
error_msg = f"❌ Error: {str(e)}"
print(error_msg)
import traceback
traceback.print_exc()
await send_telegram_notification(f"🚨 <b>Lunch Order Check Failed</b>\n\nError: {str(e)}")
raise
# ============================================
# ENTRY POINT
# ============================================
if __name__ == "__main__":
print("""
╔═══════════════════════════════════════════════════════════╗
║ 🍽️ School Lunch Ordering Script ║
╠═══════════════════════════════════════════════════════════╣
║ 1. Check if meals already ordered ║
║ 2. Order only what's missing ║
║ 3. Send Telegram notification ║
╚═══════════════════════════════════════════════════════════╝
""")
if not os.getenv("BROWSER_USE_API_KEY"):
print("⚠️ ERROR: BROWSER_USE_API_KEY not set!")
print(" Get free $10 credits at: https://cloud.browser-use.com/new-api-key")
exit(1)
if not CUSTOMER_ID or not PASSWORD:
print("⚠️ ERROR: Credentials not set!")
exit(1)
asyncio.run(order_school_lunch())
#!/bin/bash
# ============================================
# School Lunch Ordering - Cloud Version
# ============================================
#
# Uses Browser-Use Cloud - no local browser needed!
# Get free API key: https://cloud.browser-use.com/new-api-key
#
# Usage: ./run_cloud.sh
# ============================================
# School lunch credentials
export LUNCH_CUSTOMER_ID=""
export LUNCH_PASSWORD=""
# Telegram notification
export TELEGRAM_BOT_TOKEN=""
export TELEGRAM_CHAT_ID=""
# Browser-Use API key (get free $10 at https://cloud.browser-use.com/new-api-key)
# This replaces OpenAI - Browser-Use provides both LLM and browser!
export BROWSER_USE_API_KEY=""
echo "🍽️ Starting School Lunch Ordering (Cloud Version)..."
echo ""
python3 order_lunch.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment