{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Wear Aware - Proof of Concept\n",
    "BFH | BCS FS26 | Team Wear Aware\n",
    "\n",
    "Dieses Notebook zeigt, wie unsere App Wetterdaten holt und daraus eine Outfit-Empfehlung macht. Es ist bewusst einfach gehalten und deckt nur den Kern ab:\n",
    "\n",
    "- Wetterdaten über die Open-Meteo API laden\n",
    "- Outfit je nach Temperatur, Regen und Wind empfehlen\n",
    "- UV-Index bewerten und Schutz empfehlen\n",
    "- Ein paar einfache Grafiken zum Tagesverlauf\n",
    "\n",
    "Die App selbst (Mobile UI, Datenbank, Login) ist hier nicht dabei – das zeigen wir im Figma-Prototyp und im technischen Konzept."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "from datetime import datetime"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Wetterdaten holen\n",
    "\n",
    "Wir nutzen die **Open-Meteo API** – die ist gratis und braucht keinen API-Key. Dokumentation: https://open-meteo.com/en/docs\n",
    "\n",
    "Als Standort nehmen wir Bern. In der echten App würde das natürlich über GPS laufen."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Bern\n",
    "LAT = 46.948\n",
    "LON = 7.447\n",
    "STADT = \"Bern\"\n",
    "\n",
    "\n",
    "def wetter_laden(lat, lon):\n",
    "    \"\"\"Holt Wetterdaten von Open-Meteo für den angegebenen Standort.\"\"\"\n",
    "    url = \"https://api.open-meteo.com/v1/forecast\"\n",
    "    params = {\n",
    "        \"latitude\": lat,\n",
    "        \"longitude\": lon,\n",
    "        \"hourly\": \"temperature_2m,apparent_temperature,precipitation_probability,windspeed_10m,uv_index\",\n",
    "        \"current_weather\": True,\n",
    "        \"timezone\": \"Europe/Zurich\",\n",
    "        \"forecast_days\": 1\n",
    "    }\n",
    "    r = requests.get(url, params=params, timeout=10)\n",
    "    return r.json()\n",
    "\n",
    "\n",
    "# Beispieldaten für einen Apriltag in Bern (falls die API nicht geht)\n",
    "def beispieldaten():\n",
    "    heute = datetime.now().replace(minute=0, second=0, microsecond=0)\n",
    "    return {\n",
    "        \"current_weather\": {\"temperature\": 14.5, \"windspeed\": 18},\n",
    "        \"hourly\": {\n",
    "            \"time\": [heute.replace(hour=h).isoformat() for h in range(24)],\n",
    "            \"temperature_2m\":            [7, 6.5, 6, 6, 6, 6.5, 7.5, 9, 11, 13, 14.5, 15.5, 16, 16.5, 16, 15.5, 14.5, 13, 11.5, 10.5, 9.5, 9, 8.5, 8],\n",
    "            \"apparent_temperature\":      [5.5, 5, 4.5, 4.5, 4.5, 5, 6, 7.5, 9.5, 11.5, 13, 14, 14.5, 15, 14.5, 14, 13, 11.5, 10, 9, 8, 7.5, 7, 6.5],\n",
    "            \"precipitation_probability\": [10, 10, 5, 5, 5, 5, 10, 15, 25, 40, 55, 70, 75, 70, 55, 40, 25, 15, 10, 10, 5, 5, 5, 5],\n",
    "            \"windspeed_10m\":             [8, 7, 6, 6, 6, 7, 9, 12, 15, 20, 25, 30, 32, 30, 27, 22, 18, 14, 11, 10, 9, 8, 7, 7],\n",
    "            \"uv_index\":                  [0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4.5, 5, 4.5, 4, 3, 2, 1, 0.5, 0, 0, 0, 0, 0]\n",
    "        }\n",
    "    }\n",
    "\n",
    "\n",
    "# API probieren, sonst Beispieldaten nehmen\n",
    "try:\n",
    "    daten = wetter_laden(LAT, LON)\n",
    "    print(f\"Daten von Open-Meteo geladen ({STADT})\")\n",
    "except Exception as e:\n",
    "    print(f\"API nicht erreichbar ({e}), nehme Beispieldaten\")\n",
    "    daten = beispieldaten()\n",
    "\n",
    "# In einen DataFrame packen, das ist einfacher zum Arbeiten\n",
    "df = pd.DataFrame(daten[\"hourly\"])\n",
    "df[\"time\"] = pd.to_datetime(df[\"time\"])\n",
    "\n",
    "df.head(12)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Outfit-Empfehlung\n",
    "\n",
    "Die Logik ist einfach: je nach gefühlter Temperatur, Regen und Wind geben wir eine Empfehlung zurück.\n",
    "\n",
    "Wir nehmen die **gefühlte Temperatur** und nicht die normale, weil die besser beschreibt, wie sich das Wetter tatsächlich anfühlt (Wind macht kälter, Sonne wärmer)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def outfit_empfehlung(gefuehlte_temp):\n",
    "    \"\"\"Gibt eine Empfehlung anhand der gefühlten Temperatur zurück.\"\"\"\n",
    "\n",
    "    if gefuehlte_temp <= 0:\n",
    "        return {\n",
    "            \"kategorie\": \"Sehr kalt\",\n",
    "            \"kleidung\": \"Thermounterwäsche, dicker Pullover, Winterjacke\",\n",
    "            \"extras\":   \"Mütze, Schal, Handschuhe\"\n",
    "        }\n",
    "    elif gefuehlte_temp <= 8:\n",
    "        return {\n",
    "            \"kategorie\": \"Kalt\",\n",
    "            \"kleidung\": \"Langarmshirt, Pullover, warme Jacke\",\n",
    "            \"extras\":   \"Mütze oder Schal empfohlen\"\n",
    "        }\n",
    "    elif gefuehlte_temp <= 15:\n",
    "        return {\n",
    "            \"kategorie\": \"Kühl\",\n",
    "            \"kleidung\": \"Langarmshirt oder Hoodie, Übergangsjacke\",\n",
    "            \"extras\":   \"-\"\n",
    "        }\n",
    "    elif gefuehlte_temp <= 22:\n",
    "        return {\n",
    "            \"kategorie\": \"Mild\",\n",
    "            \"kleidung\": \"T-Shirt, leichte Jacke optional\",\n",
    "            \"extras\":   \"-\"\n",
    "        }\n",
    "    else:\n",
    "        return {\n",
    "            \"kategorie\": \"Warm\",\n",
    "            \"kleidung\": \"T-Shirt, Shorts oder leichtes Kleid\",\n",
    "            \"extras\":   \"-\"\n",
    "        }\n",
    "\n",
    "\n",
    "def regen_tipp(regen_prozent):\n",
    "    if regen_prozent >= 70:\n",
    "        return \"Regenjacke und Schirm mitnehmen\"\n",
    "    elif regen_prozent >= 40:\n",
    "        return \"Regenjacke oder Schirm empfohlen\"\n",
    "    elif regen_prozent >= 20:\n",
    "        return \"Ein kleiner Schirm kann nicht schaden\"\n",
    "    else:\n",
    "        return \"Kein Regenschutz nötig\"\n",
    "\n",
    "\n",
    "def wind_tipp(wind_kmh):\n",
    "    if wind_kmh >= 50:\n",
    "        return \"Sehr windig, winddichte Kleidung anziehen\"\n",
    "    elif wind_kmh >= 30:\n",
    "        return \"Stark windig, Windjacke empfohlen\"\n",
    "    elif wind_kmh >= 15:\n",
    "        return \"Etwas windig, leichte Jacke ist sinnvoll\"\n",
    "    else:\n",
    "        return \"Kaum Wind\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. UV-Index Bewertung\n",
    "\n",
    "Die WHO teilt den UV-Index in 5 Stufen ein. Wir geben je nach Stufe eine passende Empfehlung zurück."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def uv_warnung(uv):\n",
    "    \"\"\"Bewertet den UV-Index nach WHO-Stufen.\"\"\"\n",
    "\n",
    "    if uv < 3:\n",
    "        return {\n",
    "            \"stufe\":     \"Niedrig\",\n",
    "            \"nachricht\": \"Kein Schutz nötig\",\n",
    "            \"schutz\":    \"Normale Kleidung reicht\"\n",
    "        }\n",
    "    elif uv < 6:\n",
    "        return {\n",
    "            \"stufe\":     \"Mässig\",\n",
    "            \"nachricht\": \"Schutz empfohlen, vor allem mittags\",\n",
    "            \"schutz\":    \"Sonnencreme LSF 15-30\"\n",
    "        }\n",
    "    elif uv < 8:\n",
    "        return {\n",
    "            \"stufe\":     \"Hoch\",\n",
    "            \"nachricht\": \"Schutz notwendig, Mittagssonne meiden\",\n",
    "            \"schutz\":    \"Sonnencreme LSF 30+, Hut, Sonnenbrille\"\n",
    "        }\n",
    "    elif uv < 11:\n",
    "        return {\n",
    "            \"stufe\":     \"Sehr hoch\",\n",
    "            \"nachricht\": \"Hohe Gefahr, Sonne möglichst meiden\",\n",
    "            \"schutz\":    \"LSF 50+, lange Kleidung, Hut\"\n",
    "        }\n",
    "    else:\n",
    "        return {\n",
    "            \"stufe\":     \"Extrem\",\n",
    "            \"nachricht\": \"Nicht in die Sonne\",\n",
    "            \"schutz\":    \"Maximaler Schutz, Schatten suchen\"\n",
    "        }"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. Empfehlung für jetzt ausgeben\n",
    "\n",
    "Wir nehmen die Wetterdaten der aktuellen Stunde und lassen die Funktionen von oben laufen."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "jetzt = datetime.now()\n",
    "\n",
    "# Die Zeile aus dem DataFrame holen, die zur aktuellen Stunde passt\n",
    "jetzige_stunde = df[df[\"time\"].dt.hour == jetzt.hour].iloc[0]\n",
    "\n",
    "temp     = jetzige_stunde[\"temperature_2m\"]\n",
    "gefuehlt = jetzige_stunde[\"apparent_temperature\"]\n",
    "regen    = jetzige_stunde[\"precipitation_probability\"]\n",
    "wind     = jetzige_stunde[\"windspeed_10m\"]\n",
    "uv       = jetzige_stunde[\"uv_index\"]\n",
    "\n",
    "outfit  = outfit_empfehlung(gefuehlt)\n",
    "uv_info = uv_warnung(uv)\n",
    "\n",
    "print(\"=\" * 50)\n",
    "print(f\"Wear Aware - {STADT}\")\n",
    "print(f\"Stand: {jetzt.strftime('%d.%m.%Y %H:%M')}\")\n",
    "print(\"=\" * 50)\n",
    "print(f\"Temperatur: {temp}°C (gefühlt {gefuehlt}°C)\")\n",
    "print(f\"Regen: {regen}%\")\n",
    "print(f\"Wind: {wind} km/h\")\n",
    "print(f\"UV: {uv}\")\n",
    "print()\n",
    "print(f\"Kategorie: {outfit['kategorie']}\")\n",
    "print(f\"Kleidung:  {outfit['kleidung']}\")\n",
    "if outfit[\"extras\"] != \"-\":\n",
    "    print(f\"Extras:    {outfit['extras']}\")\n",
    "print()\n",
    "print(f\"Regen: {regen_tipp(regen)}\")\n",
    "print(f\"Wind:  {wind_tipp(wind)}\")\n",
    "print()\n",
    "print(f\"UV ({uv_info['stufe']}): {uv_info['nachricht']}\")\n",
    "print(f\"Schutz: {uv_info['schutz']}\")\n",
    "print(\"=\" * 50)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. Personalisierung\n",
    "\n",
    "Manche Leute frieren schneller, andere sind hitzeempfindlich. Wir rechnen einen Offset auf die gefühlte Temperatur dazu und bekommen so eine angepasste Empfehlung. Einfach aber funktioniert."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "profile = {\n",
    "    \"Normal\":           0,\n",
    "    \"Friert schnell\":  -3,\n",
    "    \"Hitzeempfindlich\": 3\n",
    "}\n",
    "\n",
    "print(f\"Gefühlte Temperatur jetzt: {gefuehlt}°C\\n\")\n",
    "\n",
    "for name, offset in profile.items():\n",
    "    angepasst = gefuehlt + offset\n",
    "    o = outfit_empfehlung(angepasst)\n",
    "    print(f\"{name} (Offset {offset:+d}°C -> {angepasst:.1f}°C):\")\n",
    "    print(f\"  {o['kategorie']} | {o['kleidung']}\")\n",
    "    print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 7. Grafiken zum Tagesverlauf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "stunden = df[\"time\"].dt.hour\n",
    "\n",
    "fig, axes = plt.subplots(2, 2, figsize=(12, 7))\n",
    "\n",
    "# Temperatur\n",
    "axes[0, 0].plot(stunden, df[\"temperature_2m\"], label=\"Temperatur\", color=\"red\", marker=\"o\")\n",
    "axes[0, 0].plot(stunden, df[\"apparent_temperature\"], label=\"gefühlt\", color=\"orange\", linestyle=\"--\")\n",
    "axes[0, 0].set_title(\"Temperatur (°C)\")\n",
    "axes[0, 0].set_xlabel(\"Stunde\")\n",
    "axes[0, 0].legend()\n",
    "axes[0, 0].grid(True)\n",
    "\n",
    "# Regen\n",
    "axes[0, 1].bar(stunden, df[\"precipitation_probability\"], color=\"steelblue\")\n",
    "axes[0, 1].set_title(\"Regenwahrscheinlichkeit (%)\")\n",
    "axes[0, 1].set_xlabel(\"Stunde\")\n",
    "axes[0, 1].set_ylim(0, 100)\n",
    "axes[0, 1].grid(True, axis=\"y\")\n",
    "\n",
    "# Wind\n",
    "axes[1, 0].plot(stunden, df[\"windspeed_10m\"], color=\"green\", marker=\"o\")\n",
    "axes[1, 0].set_title(\"Wind (km/h)\")\n",
    "axes[1, 0].set_xlabel(\"Stunde\")\n",
    "axes[1, 0].grid(True)\n",
    "\n",
    "# UV\n",
    "axes[1, 1].plot(stunden, df[\"uv_index\"], color=\"purple\", marker=\"s\")\n",
    "axes[1, 1].set_title(\"UV-Index\")\n",
    "axes[1, 1].set_xlabel(\"Stunde\")\n",
    "axes[1, 1].grid(True)\n",
    "\n",
    "plt.suptitle(f\"Tagesverlauf {STADT} - {jetzt.strftime('%d.%m.%Y')}\", fontsize=13)\n",
    "plt.tight_layout()\n",
    "plt.savefig(\"wearaware_plots.png\", dpi=100)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 8. Fazit\n",
    "\n",
    "Der PoC zeigt, dass:\n",
    "\n",
    "- Wir über Open-Meteo alle benötigten Wetterdaten ohne Kosten bekommen\n",
    "- Die Outfit-Logik mit einfachen if-elif-Regeln gut funktioniert\n",
    "- UV-Warnungen mit der WHO-Einteilung direkt umsetzbar sind\n",
    "- Eine einfache Personalisierung (Offset) schon einen Unterschied macht\n",
    "\n",
    "**Was hier nicht drin ist** (aber in der echten App kommt):\n",
    "\n",
    "- Mobile UI (siehe Figma-Prototyp)\n",
    "- Datenbank für Nutzerkonten und Kleiderschrank\n",
    "- Login und GPS-Standort\n",
    "- Reiseplanung mit mehrtägiger Vorhersage\n",
    "- Push-Benachrichtigungen"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
