Personalisiertes Wetter-E-Mail mit Python und AI
Dies ist ein Personal Productivity, Multimodal AI-Bereich Automatisierungsworkflow mit 11 Nodes. Hauptsächlich werden Code, Gmail, FormTrigger, HttpRequest, Agent und andere Nodes verwendet. OpenWeatherMap, Python und GPT-4.1-mini zum Generieren personalisierter Wetterberichte verwenden
- •Google-Konto + Gmail API-Anmeldedaten
- •Möglicherweise sind Ziel-API-Anmeldedaten erforderlich
- •OpenAI API Key
Verwendete Nodes (11)
{
"id": "BrYg4iQRGkBoypeu",
"meta": {
"instanceId": "bdc54da2c96840612a04bf3fd3a4cd97a7a7bd7c1152bbe41d5615f09311c097",
"templateCredsSetupCompleted": true
},
"name": "Custom Weather Email using Python and AI",
"tags": [],
"nodes": [
{
"id": "822a0d12-4591-40d0-85f9-0c940372ed5f",
"name": "Wetterdaten abrufen",
"type": "n8n-nodes-base.httpRequest",
"position": [
-80,
304
],
"parameters": {
"url": "https://api.openweathermap.org/data/2.5/weather",
"options": {},
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "=q",
"value": "={{ $json.City }}"
},
{
"name": "appid",
"value": "<your_API_key>"
},
{
"name": "units",
"value": "metric"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "99ddfbb3-c834-4017-9ec4-f32f870e1482",
"name": "Wetterdaten verarbeiten",
"type": "n8n-nodes-base.code",
"position": [
32,
496
],
"parameters": {
"language": "python",
"pythonCode": "import json\nfrom datetime import datetime\nimport math\n\n# Get the weather data from the previous node\nweather_data = items[0]['json']\n\n# Extract relevant information\ncity = weather_data['name']\ncountry = weather_data['sys']['country']\ntemperature = weather_data['main']['temp']\nfeels_like = weather_data['main']['feels_like']\nhumidity = weather_data['main']['humidity']\npressure = weather_data['main']['pressure']\ndescription = weather_data['weather'][0]['description']\nwind_speed = weather_data['wind']['speed']\nvisibility = weather_data.get('visibility', 0) / 1000 # Convert to km\n\n# Calculate temperature in Fahrenheit\ntemp_fahrenheit = (temperature * 9/5) + 32\nfeels_like_fahrenheit = (feels_like * 9/5) + 32\n\n# Calculate wind speed in different units\nwind_speed_kmh = wind_speed * 3.6\nwind_speed_mph = wind_speed * 2.237\n\n# Determine comfort level based on temperature and humidity\ndef get_comfort_level(temp, humidity):\n if temp < 0:\n return \"Freezing\"\n elif temp < 10:\n return \"Cold\"\n elif temp > 35:\n return \"Very Hot\"\n elif temp > 28:\n return \"Hot\"\n elif humidity > 80:\n return \"Humid\"\n elif 18 <= temp <= 24 and 40 <= humidity <= 60:\n return \"Ideal\"\n elif 15 <= temp <= 27 and humidity <= 70:\n return \"Comfortable\"\n else:\n return \"Moderate\"\n\n# Get clothing suggestion\ndef get_clothing_suggestion(temp, wind, desc):\n if \"rain\" in desc.lower() or \"drizzle\" in desc.lower():\n clothing = \"Waterproof jacket and umbrella\"\n elif \"snow\" in desc.lower():\n clothing = \"Heavy winter coat, boots, gloves, and hat\"\n elif temp < 0:\n clothing = \"Heavy winter coat, thermal layers, gloves, and hat\"\n elif temp < 10:\n clothing = \"Warm jacket or heavy sweater\"\n elif temp < 18:\n clothing = \"Light jacket or cardigan\"\n elif temp < 25:\n clothing = \"Long sleeves or light sweater\"\n elif temp < 30:\n clothing = \"T-shirt and light pants/shorts\"\n else:\n clothing = \"Light, breathable clothing and sun protection\"\n \n if wind > 5:\n clothing += \" (consider wind protection)\"\n \n return clothing\n\n# Get activity recommendation\ndef get_activity_recommendation(temp, desc, wind):\n desc_lower = desc.lower()\n \n if \"thunderstorm\" in desc_lower or \"heavy rain\" in desc_lower:\n return \"Stay indoors, perfect for indoor activities\"\n elif \"rain\" in desc_lower or \"drizzle\" in desc_lower:\n return \"Indoor activities recommended, or covered outdoor areas\"\n elif \"snow\" in desc_lower:\n return \"Winter sports, snowman building, or cozy indoor activities\"\n elif temp < -5:\n return \"Limit outdoor exposure, indoor activities recommended\"\n elif temp < 5:\n return \"Short outdoor activities, winter sports, or indoor activities\"\n elif 15 <= temp <= 25 and wind < 7:\n return \"Perfect for any outdoor activities - hiking, sports, picnics\"\n elif temp > 30:\n return \"Early morning or evening outdoor activities, stay hydrated\"\n elif wind > 10:\n return \"Be cautious with outdoor activities, secure loose items\"\n else:\n return \"Good for moderate outdoor activities\"\n\n# Determine weather emoji\ndef get_weather_emoji(desc):\n desc_lower = desc.lower()\n if \"clear\" in desc_lower:\n return \"☀️\"\n elif \"cloud\" in desc_lower:\n return \"☁️\" if \"few\" not in desc_lower else \"⛅\"\n elif \"rain\" in desc_lower:\n return \"🌧️\"\n elif \"thunderstorm\" in desc_lower:\n return \"⛈️\"\n elif \"snow\" in desc_lower:\n return \"❄️\"\n elif \"mist\" in desc_lower or \"fog\" in desc_lower:\n return \"🌫️\"\n else:\n return \"🌤️\"\n\ncomfort_level = get_comfort_level(temperature, humidity)\nweather_emoji = get_weather_emoji(description)\n\n# Create a comprehensive weather report\nweather_report = {\n \"location\": f\"{city}, {country}\",\n \"timestamp\": datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\"),\n \"weather_emoji\": weather_emoji,\n \"current_conditions\": {\n \"temperature_celsius\": round(temperature, 1),\n \"temperature_fahrenheit\": round(temp_fahrenheit, 1),\n \"feels_like_celsius\": round(feels_like, 1),\n \"feels_like_fahrenheit\": round(feels_like_fahrenheit, 1),\n \"description\": description.title(),\n \"humidity\": humidity,\n \"pressure\": pressure,\n \"visibility_km\": round(visibility, 1),\n \"wind_speed_ms\": round(wind_speed, 1),\n \"wind_speed_kmh\": round(wind_speed_kmh, 1),\n \"wind_speed_mph\": round(wind_speed_mph, 1)\n },\n \"analysis\": {\n \"comfort_level\": comfort_level,\n \"is_good_weather\": temperature >= 15 and temperature <= 25 and humidity <= 70 and \"rain\" not in description.lower(),\n \"clothing_suggestion\": get_clothing_suggestion(temperature, wind_speed, description),\n \"activity_recommendation\": get_activity_recommendation(temperature, description, wind_speed),\n \"weather_quality_score\": min(100, max(0, \n 100 - abs(20 - temperature) * 3 - max(0, humidity - 60) - max(0, wind_speed - 5) * 5\n ))\n },\n \"raw_data\": weather_data\n}\n\n# Return the processed data\nreturn [{\"json\": weather_report}]"
},
"typeVersion": 2
},
{
"id": "0d850dd1-2930-407f-9f87-f418bc588f4a",
"name": "E-Mail-Inhalt generieren",
"type": "n8n-nodes-base.code",
"position": [
160,
320
],
"parameters": {
"language": "python",
"pythonCode": "# Get the processed weather data\nweather_data = items[0]['json']\n\n# Create HTML email content\nhtml_content = f\"\"\"\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Weather Report</title>\n <style>\n body {{ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background-color: #f5f7fa; }}\n .container {{ max-width: 600px; margin: 0 auto; background-color: white; border-radius: 15px; overflow: hidden; box-shadow: 0 10px 30px rgba(0,0,0,0.1); }}\n .header {{ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; text-align: center; }}\n .header h1 {{ margin: 0; font-size: 2em; }}\n .location {{ font-size: 1.2em; margin-top: 10px; opacity: 0.9; }}\n .section {{ padding: 25px; border-bottom: 1px solid #eee; }}\n .section:last-child {{ border-bottom: none; }}\n .section h2 {{ color: #2c3e50; margin-top: 0; display: flex; align-items: center; gap: 10px; }}\n .temp-main {{ font-size: 3em; font-weight: bold; color: #e74c3c; text-align: center; margin: 20px 0; }}\n .temp-feels {{ font-size: 1.2em; color: #7f8c8d; text-align: center; margin-bottom: 20px; }}\n .conditions-grid {{ display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin: 20px 0; }}\n .condition-item {{ background-color: #f8f9fa; padding: 15px; border-radius: 8px; text-align: center; }}\n .condition-value {{ font-size: 1.4em; font-weight: bold; color: #2c3e50; }}\n .condition-label {{ font-size: 0.9em; color: #7f8c8d; margin-top: 5px; }}\n .comfort-badge {{ display: inline-block; padding: 8px 16px; border-radius: 20px; font-weight: bold; text-transform: uppercase; font-size: 0.9em; }}\n .comfort-ideal {{ background-color: #d4edda; color: #155724; }}\n .comfort-comfortable {{ background-color: #cce5ff; color: #004085; }}\n .comfort-moderate {{ background-color: #fff3cd; color: #856404; }}\n .comfort-hot {{ background-color: #f8d7da; color: #721c24; }}\n .comfort-cold {{ background-color: #e2e3e5; color: #383d41; }}\n .recommendation {{ background-color: #e8f5e8; padding: 20px; border-radius: 10px; margin: 15px 0; border-left: 4px solid #28a745; }}\n .score {{ text-align: center; margin: 20px 0; }}\n .score-circle {{ display: inline-block; width: 80px; height: 80px; border-radius: 50%; background: conic-gradient(#28a745 0deg {weather_data['analysis']['weather_quality_score'] * 3.6}deg, #e9ecef {weather_data['analysis']['weather_quality_score'] * 3.6}deg 360deg); position: relative; }}\n .score-inner {{ position: absolute; top: 10px; left: 10px; width: 60px; height: 60px; border-radius: 50%; background-color: white; display: flex; align-items: center; justify-content: center; font-weight: bold; color: #2c3e50; }}\n .footer {{ background-color: #f8f9fa; padding: 20px; text-align: center; font-size: 0.9em; color: #6c757d; }}\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <h1>{weather_data['weather_emoji']} Weather Report</h1>\n <div class=\"location\">{weather_data['location']}</div>\n <div style=\"font-size: 0.9em; margin-top: 5px;\">{weather_data['timestamp']}</div>\n </div>\n \n <div class=\"section\">\n <div class=\"temp-main\">{weather_data['current_conditions']['temperature_celsius']}°C</div>\n <div class=\"temp-feels\">Feels like {weather_data['current_conditions']['feels_like_celsius']}°C</div>\n <div style=\"text-align: center; font-size: 1.3em; color: #495057; margin-bottom: 20px;\">\n {weather_data['current_conditions']['description']}\n </div>\n \n <div style=\"text-align: center; margin: 20px 0;\">\n <span class=\"comfort-badge comfort-{weather_data['analysis']['comfort_level'].lower().replace(' ', '-')}\">\n {weather_data['analysis']['comfort_level']}\n </span>\n </div>\n </div>\n \n <div class=\"section\">\n <h2>📊 Current Conditions</h2>\n <div class=\"conditions-grid\">\n <div class=\"condition-item\">\n <div class=\"condition-value\">{weather_data['current_conditions']['humidity']}%</div>\n <div class=\"condition-label\">Humidity</div>\n </div>\n <div class=\"condition-item\">\n <div class=\"condition-value\">{weather_data['current_conditions']['pressure']}</div>\n <div class=\"condition-label\">Pressure (hPa)</div>\n </div>\n <div class=\"condition-item\">\n <div class=\"condition-value\">{weather_data['current_conditions']['wind_speed_kmh']}</div>\n <div class=\"condition-label\">Wind (km/h)</div>\n </div>\n <div class=\"condition-item\">\n <div class=\"condition-value\">{weather_data['current_conditions']['visibility_km']}</div>\n <div class=\"condition-label\">Visibility (km)</div>\n </div>\n </div>\n </div>\n \n <div class=\"section\">\n <h2>🎯 Recommendations</h2>\n <div class=\"recommendation\">\n <strong>👕 What to Wear:</strong><br>\n {weather_data['analysis']['clothing_suggestion']}\n </div>\n <div class=\"recommendation\">\n <strong>🏃 Activities:</strong><br>\n {weather_data['analysis']['activity_recommendation']}\n </div>\n </div>\n \n <div class=\"section\">\n <h2>⭐ Weather Quality Score</h2>\n <div class=\"score\">\n <div class=\"score-circle\">\n <div class=\"score-inner\">{int(weather_data['analysis']['weather_quality_score'])}</div>\n </div>\n <div style=\"margin-top: 10px; color: #6c757d;\">Out of 100</div>\n </div>\n </div>\n \n <div class=\"footer\">\n <strong>🤖 Generated by n8n Weather Pipeline</strong><br>\n Powered by Python • OpenWeatherMap API<br>\n <em>Stay informed, stay prepared!</em>\n </div>\n </div>\n</body>\n</html>\n\"\"\"\n\n# Create plain text version\ntext_content = f\"\"\"\n🌤️ DAILY WEATHER REPORT\n\n📍 Location: {weather_data['location']}\n🕒 Time: {weather_data['timestamp']}\n\n🌡️ CURRENT CONDITIONS\n- Temperature: {weather_data['current_conditions']['temperature_celsius']}°C ({weather_data['current_conditions']['temperature_fahrenheit']}°F)\n- Feels Like: {weather_data['current_conditions']['feels_like_celsius']}°C ({weather_data['current_conditions']['feels_like_fahrenheit']}°F)\n- Condition: {weather_data['current_conditions']['description']}\n- Humidity: {weather_data['current_conditions']['humidity']}%\n- Wind Speed: {weather_data['current_conditions']['wind_speed_kmh']} km/h\n- Pressure: {weather_data['current_conditions']['pressure']} hPa\n- Visibility: {weather_data['current_conditions']['visibility_km']} km\n\n💡 ANALYSIS\n- Comfort Level: {weather_data['analysis']['comfort_level']}\n- Weather Quality Score: {int(weather_data['analysis']['weather_quality_score'])}/100\n\n👕 CLOTHING RECOMMENDATION\n{weather_data['analysis']['clothing_suggestion']}\n\n🏃 ACTIVITY RECOMMENDATION\n{weather_data['analysis']['activity_recommendation']}\n\n---\nGenerated by n8n Weather Pipeline\nPowered by Python & OpenWeatherMap API\n\"\"\"\n\n# Return the email content\nreturn [{\n \"json\": {\n \"subject\": f\"{weather_data['weather_emoji']} Weather Report - {weather_data['location']} ({weather_data['current_conditions']['temperature_celsius']}°C)\",\n \"html_content\": html_content,\n \"text_content\": text_content,\n \"weather_data\": weather_data\n }\n}]"
},
"typeVersion": 2
},
{
"id": "22cbe6d0-2360-4039-a7b5-fc242c3061ff",
"name": "Nachricht senden",
"type": "n8n-nodes-base.gmail",
"position": [
800,
304
],
"webhookId": "0fa8e721-11fd-4a08-b150-d6b1c58a59f3",
"parameters": {
"sendTo": "emailAddress",
"message": "={{ $json.output }}",
"options": {},
"subject": "={{ $('Generate Email Content').item.json.subject }}"
},
"typeVersion": 2.1
},
{
"id": "0c5c9ca9-ec89-4420-ad8c-0a96ccb2b5b5",
"name": "KI-Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
384,
304
],
"parameters": {
"text": "=You are an email drafting expert. Take the weather information from {{ $json.text_content }} and make it pretty and easy to read. Use proper spacing, use of paragraphs and bullet points.\n\nPrepare your email in html format.\n\nAdd a joke relevant to the weather if possible. ",
"options": {},
"promptType": "define"
},
"typeVersion": 2.1
},
{
"id": "1557d3ed-d6fa-4542-ab01-961873998ca4",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
432,
512
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-mini"
},
"options": {}
},
"typeVersion": 1.2
},
{
"id": "eccbbc05-da0c-40b9-8954-3f0fadb0640f",
"name": "Bei Formularübermittlung",
"type": "n8n-nodes-base.formTrigger",
"position": [
-320,
304
],
"webhookId": "28ccc6a1-25c4-4f3c-9358-4365285f7cdf",
"parameters": {
"options": {},
"formTitle": "Enter a City",
"formFields": {
"values": [
{
"fieldLabel": "City",
"placeholder": "New York"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "52859605-1f9d-4e87-a722-920ac296095b",
"name": "Haftnotiz",
"type": "n8n-nodes-base.stickyNote",
"position": [
-400,
192
],
"parameters": {
"height": 304,
"content": "Enter the name of a city in the form"
},
"typeVersion": 1
},
{
"id": "bcd1c3e0-ee2d-479d-9fc4-1d391d20c0e9",
"name": "Haftnotiz1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-144,
176
],
"parameters": {
"width": 480,
"height": 464,
"content": "Add OpenWeather API key to get current weather information about the cit, replace <your_API_key> with your actual API key. \nPython script will process and generate custom email relating to the weather. "
},
"typeVersion": 1
},
{
"id": "49c4cdfb-13ea-41fa-90bc-7ced8147fc19",
"name": "Haftnotiz2",
"type": "n8n-nodes-base.stickyNote",
"position": [
352,
176
],
"parameters": {
"width": 352,
"height": 480,
"content": "Add OpenAI API Key. AI Agent will add a custom joke about the weather for the city you entered as part of the email message"
},
"typeVersion": 1
},
{
"id": "46ed9532-4693-4740-819f-81a1ddf51ca1",
"name": "Haftnotiz3",
"type": "n8n-nodes-base.stickyNote",
"position": [
720,
176
],
"parameters": {
"height": 304,
"content": "Add your Gmail credentials and update header and body of message. Node will send the custom email to the recipient"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "83a69a4e-f4cd-472f-812e-1492a06ddbc5",
"connections": {
"0c5c9ca9-ec89-4420-ad8c-0a96ccb2b5b5": {
"main": [
[
{
"node": "22cbe6d0-2360-4039-a7b5-fc242c3061ff",
"type": "main",
"index": 0
}
]
]
},
"1557d3ed-d6fa-4542-ab01-961873998ca4": {
"ai_languageModel": [
[
{
"node": "0c5c9ca9-ec89-4420-ad8c-0a96ccb2b5b5",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"822a0d12-4591-40d0-85f9-0c940372ed5f": {
"main": [
[
{
"node": "99ddfbb3-c834-4017-9ec4-f32f870e1482",
"type": "main",
"index": 0
}
]
]
},
"eccbbc05-da0c-40b9-8954-3f0fadb0640f": {
"main": [
[
{
"node": "822a0d12-4591-40d0-85f9-0c940372ed5f",
"type": "main",
"index": 0
}
]
]
},
"99ddfbb3-c834-4017-9ec4-f32f870e1482": {
"main": [
[
{
"node": "0d850dd1-2930-407f-9f87-f418bc588f4a",
"type": "main",
"index": 0
}
]
]
},
"0d850dd1-2930-407f-9f87-f418bc588f4a": {
"main": [
[
{
"node": "0c5c9ca9-ec89-4420-ad8c-0a96ccb2b5b5",
"type": "main",
"index": 0
}
]
]
}
}
}Wie verwende ich diesen Workflow?
Kopieren Sie den obigen JSON-Code, erstellen Sie einen neuen Workflow in Ihrer n8n-Instanz und wählen Sie "Aus JSON importieren". Fügen Sie die Konfiguration ein und passen Sie die Anmeldedaten nach Bedarf an.
Für welche Szenarien ist dieser Workflow geeignet?
Fortgeschritten - Persönliche Produktivität, Multimodales KI
Ist es kostenpflichtig?
Dieser Workflow ist völlig kostenlos. Beachten Sie jedoch, dass Drittanbieterdienste (wie OpenAI API), die im Workflow verwendet werden, möglicherweise kostenpflichtig sind.
Verwandte Workflows
Moe Ahad
@moe-ahadDiesen Workflow teilen