diff --git a/package-lock.json b/package-lock.json
index b21831104580c92057ec06df33efe494847e2289..e4df3eccd6e7538b784c31b5f9618101302f572b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
         "@types/react-dom": "^18.2.6",
         "framer-motion": "^10.16.16",
         "javascript-time-ago": "^2.5.9",
+        "openmeteo": "^1.1.3",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "react-error-boundary": "^4.0.11",
@@ -3223,6 +3224,22 @@
         "node": ">= 8"
       }
     },
+    "node_modules/@openmeteo/sdk": {
+      "version": "1.11.4",
+      "resolved": "https://registry.npmjs.org/@openmeteo/sdk/-/sdk-1.11.4.tgz",
+      "integrity": "sha512-9So53FQMP+27rPzsJXisH6Ks4pow1Unr6mIk4yM6RD2BeWk0Xibd7Sj3UzYrBAeDf7fTzBvLisbhA9cgzs85fw==",
+      "dependencies": {
+        "flatbuffers": "^24.3.25"
+      },
+      "engines": {
+        "node": ">=12.0"
+      }
+    },
+    "node_modules/@openmeteo/sdk/node_modules/flatbuffers": {
+      "version": "24.3.25",
+      "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-24.3.25.tgz",
+      "integrity": "sha512-3HDgPbgiwWMI9zVB7VYBHaMrbOO7Gm0v+yD2FV/sCKj+9NDeVL7BOBYUuhWAQGKWOzBo8S9WdMvV0eixO233XQ=="
+    },
     "node_modules/@phosphor-icons/react": {
       "version": "2.0.15",
       "resolved": "https://registry.npmjs.org/@phosphor-icons/react/-/react-2.0.15.tgz",
@@ -8067,6 +8084,11 @@
         "node": "^10.12.0 || >=12.0.0"
       }
     },
+    "node_modules/flatbuffers": {
+      "version": "23.5.26",
+      "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-23.5.26.tgz",
+      "integrity": "sha512-vE+SI9vrJDwi1oETtTIFldC/o9GsVKRM+s6EL0nQgxXlYV1Vc4Tk30hj4xGICftInKQKj1F3up2n8UbIVobISQ=="
+    },
     "node_modules/flatted": {
       "version": "3.2.7",
       "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
@@ -12463,6 +12485,18 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/openmeteo": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/openmeteo/-/openmeteo-1.1.3.tgz",
+      "integrity": "sha512-f4ycmEA9rnhH4mPkDSLAuZ9dCu33nZ2bP7pLUJmZp2YYAuIDrGDIWU/VXQPmG48l5s+vw0VcnH9+CMqL57oADQ==",
+      "dependencies": {
+        "@openmeteo/sdk": "^1.4.0",
+        "flatbuffers": "^23.5.26"
+      },
+      "engines": {
+        "node": ">=12.0"
+      }
+    },
     "node_modules/optionator": {
       "version": "0.9.1",
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -19511,6 +19545,21 @@
         "fastq": "^1.6.0"
       }
     },
+    "@openmeteo/sdk": {
+      "version": "1.11.4",
+      "resolved": "https://registry.npmjs.org/@openmeteo/sdk/-/sdk-1.11.4.tgz",
+      "integrity": "sha512-9So53FQMP+27rPzsJXisH6Ks4pow1Unr6mIk4yM6RD2BeWk0Xibd7Sj3UzYrBAeDf7fTzBvLisbhA9cgzs85fw==",
+      "requires": {
+        "flatbuffers": "^24.3.25"
+      },
+      "dependencies": {
+        "flatbuffers": {
+          "version": "24.3.25",
+          "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-24.3.25.tgz",
+          "integrity": "sha512-3HDgPbgiwWMI9zVB7VYBHaMrbOO7Gm0v+yD2FV/sCKj+9NDeVL7BOBYUuhWAQGKWOzBo8S9WdMvV0eixO233XQ=="
+        }
+      }
+    },
     "@phosphor-icons/react": {
       "version": "2.0.15",
       "resolved": "https://registry.npmjs.org/@phosphor-icons/react/-/react-2.0.15.tgz",
@@ -23083,6 +23132,11 @@
         "rimraf": "^3.0.2"
       }
     },
+    "flatbuffers": {
+      "version": "23.5.26",
+      "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-23.5.26.tgz",
+      "integrity": "sha512-vE+SI9vrJDwi1oETtTIFldC/o9GsVKRM+s6EL0nQgxXlYV1Vc4Tk30hj4xGICftInKQKj1F3up2n8UbIVobISQ=="
+    },
     "flatted": {
       "version": "3.2.7",
       "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
@@ -26215,6 +26269,15 @@
         "is-wsl": "^2.2.0"
       }
     },
+    "openmeteo": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/openmeteo/-/openmeteo-1.1.3.tgz",
+      "integrity": "sha512-f4ycmEA9rnhH4mPkDSLAuZ9dCu33nZ2bP7pLUJmZp2YYAuIDrGDIWU/VXQPmG48l5s+vw0VcnH9+CMqL57oADQ==",
+      "requires": {
+        "@openmeteo/sdk": "^1.4.0",
+        "flatbuffers": "^23.5.26"
+      }
+    },
     "optionator": {
       "version": "0.9.1",
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
diff --git a/package.json b/package.json
index beab91d79680ec10b03665800703486f174b4142..0a7fae1da68738352f157617306301c250f7ec2b 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
     "@types/react-dom": "^18.2.6",
     "framer-motion": "^10.16.16",
     "javascript-time-ago": "^2.5.9",
+    "openmeteo": "^1.1.3",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "react-error-boundary": "^4.0.11",
diff --git a/public/config/default.json b/public/config/default.json
index 44587bffad859d47dc5eedee52ab9beaf85638b4..245d369ca50fa44c79c4a1e18fbefe1fa510e543 100644
--- a/public/config/default.json
+++ b/public/config/default.json
@@ -63,17 +63,30 @@
       }
     },
     {
-      "type": "callout",
+      "type": "wetter",
       "position": {
         "x": 9,
         "y": 3,
-        "w": 16,
+        "w": 8,
+        "h": 2
+      },
+      "config": {
+        "latitude": 51.5149,
+        "longitude": 7.466
+      }
+    },
+    {
+      "type": "callout",
+      "position": {
+        "x": 17,
+        "y": 3,
+        "w": 8,
         "h": 2
       },
       "config": {
         "type": "warning",
         "title": "Achtung, Testbetrieb",
-        "description": "Der neue Infoscreen ist da! Bitte melde Fehler an die Admins unter root@oh14.de."
+        "description": "Bitte melde Fehler an die Admins unter root@oh14.de."
       }
     },
     {
diff --git a/src/panels/Wetter/WetterPanel.tsx b/src/panels/Wetter/WetterPanel.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..205b9ece194b79ae41317e6626b9ca984521d808
--- /dev/null
+++ b/src/panels/Wetter/WetterPanel.tsx
@@ -0,0 +1,87 @@
+import { useEffect, useState } from 'react';
+import PanelWrapper from '../../meta/PanelWrapper';
+import PanelTitle from '../../meta/PanelTitle';
+import PanelContent from '../../meta/PanelContent';
+import { Cloud, CloudFog, CloudLightning, CloudRain, CloudSnow, CloudSun, Icon, Sun } from '@phosphor-icons/react';
+import { fetchWeatherApi } from 'openmeteo';
+
+export type WetterPanelDefinition = {
+    latitude: number,
+    longitude: number,
+}
+
+const WetterPanel = (props: { definition: WetterPanelDefinition }) => {
+    const [temperature, setTemperature] = useState<number>(0);
+    const [weatherCode, setWeatherCode] = useState<number>(0);
+    // TODO: how long will it rain
+
+    useEffect(() => {
+        // this function will be called every hour
+        const update = async () => {
+            // query open-meteo (https://github.com/open-meteo/typescript)
+            const params = {
+                latitude: [props.definition.latitude],
+                longitude: [props.definition.longitude],
+                current: 'temperature_2m,precipitation,weather_code,rain,showers',
+                forecast_days: 1,
+            }
+
+            const url = 'https://api.open-meteo.com/v1/forecast';
+            const currentWeather = (await fetchWeatherApi(url, params))[0].current()!;
+
+            setTemperature(Math.round(currentWeather.variables(0)!.value()))
+            setWeatherCode(currentWeather.variables(1)!.value())
+        }
+
+        // call it manually the first time
+        update();
+        const interval = setInterval(update, 1000 * 60 * 60);
+
+        return () => {
+            // clear up old handle in case this component is cleaned up
+            clearInterval(interval)
+        }
+    });
+
+    const renderWeather = (weatherCode: number, temperature: number) => {
+        const [WeatherIcon, text] = wcToIconText(weatherCode)!;
+        return (<div className='clex-1 flex flex-row gap-2 items-center'>
+            <WeatherIcon size={32} />
+            <p>{text} <span className='text-gray-400'>{temperature}°C</span></p>
+        </div>);
+    };
+
+    return (
+        <PanelWrapper className={"relative"}>
+            <PanelTitle title={"Wetter"} />
+            <PanelContent>
+                <div className={"flex flex-row gap-4 items-center"}>
+                    {renderWeather(weatherCode, temperature)}
+                </div>
+            </PanelContent>
+        </PanelWrapper>
+    );
+};
+
+/**
+ * Take a weather code and give an icon and text for the weather
+ * @param weather_code weather code (see https://open-meteo.com/en/docs)
+ * @returns Tuple of Icon and text or undefined
+ */
+function wcToIconText(weather_code: number): [Icon, string] | undefined {
+    switch (true) {
+        case weather_code === 0: return [Sun, "Sonnig"]
+        case weather_code <= 2: return [CloudSun, "Bewölkt"]
+        case weather_code <= 3: return [Cloud, "Bedeckt"]
+        case weather_code <= 48: return [CloudFog, "Nebel"]
+        case weather_code <= 67: return [CloudRain, "Regen"]
+        case weather_code <= 77: return [CloudSnow, "Schneefall"]
+        case weather_code <= 82: return [CloudRain, "Starker Regen"]
+        case weather_code <= 86: return [CloudSnow, "Starker Schneefall"]
+        case weather_code <= 99: return [CloudLightning, "Gewitter"]
+        default: return undefined
+    }
+
+}
+
+export default WetterPanel;
diff --git a/src/panels/_Panels.tsx b/src/panels/_Panels.tsx
index eadb79eb63c536855bbcc66d8d23e05db61fafd4..426a5e4d69df2a0247d1327d5b5a80ba3f4185ca 100644
--- a/src/panels/_Panels.tsx
+++ b/src/panels/_Panels.tsx
@@ -11,6 +11,7 @@ import BildPanel from "./Bild/BildPanel";
 import MensaplanPanel from "./Mensaplan/MensaplanPanel";
 import CalloutPanel from "./Callout/CalloutPanel";
 import GremiumPanel from "./Gremium/GremiumPanel";
+import WetterPanel from "./Wetter/WetterPanel";
 
 /*
  * First, please claim a unique id for your panel here. Convention is that it is all lowercase, in snake-case to be
@@ -30,6 +31,7 @@ export const PanelRenderers: {[panelType: string]: React.FC<any & {definition: P
   "mensaplan": MensaplanPanel,
   "callout": CalloutPanel,
   "gremium": GremiumPanel,
+  "wetter": WetterPanel,
   "placeholder": () => (
     <PanelWrapper className={"flex flex-col items-center justify-center text-zinc-400"}>
       Dieses Panel wird noch entwickelt