{"id":30838678,"url":"https://github.com/lowfatprophet/wetterstation","last_synced_at":"2026-05-08T09:32:58.676Z","repository":{"id":310907037,"uuid":"1041305518","full_name":"lowfatprophet/wetterstation","owner":"lowfatprophet","description":"An exercise in fullstack development, from embedded through database and server to frontend.","archived":false,"fork":false,"pushed_at":"2025-08-29T12:46:44.000Z","size":51,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-06T18:23:39.419Z","etag":null,"topics":["fastapi","mariadb","python","python-3","uv"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lowfatprophet.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-20T09:40:35.000Z","updated_at":"2025-08-29T12:46:47.000Z","dependencies_parsed_at":"2025-08-21T00:29:07.745Z","dependency_job_id":"3edfec6a-465c-4dce-bfa5-a97fa80f3108","html_url":"https://github.com/lowfatprophet/wetterstation","commit_stats":null,"previous_names":["lowfatprophet/wetterstation"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lowfatprophet/wetterstation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lowfatprophet%2Fwetterstation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lowfatprophet%2Fwetterstation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lowfatprophet%2Fwetterstation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lowfatprophet%2Fwetterstation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lowfatprophet","download_url":"https://codeload.github.com/lowfatprophet/wetterstation/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lowfatprophet%2Fwetterstation/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32774854,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-08T08:22:46.396Z","status":"ssl_error","status_checked_at":"2026-05-08T08:22:45.650Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastapi","mariadb","python","python-3","uv"],"created_at":"2025-09-06T18:05:23.688Z","updated_at":"2026-05-08T09:32:58.656Z","avatar_url":"https://github.com/lowfatprophet.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Wetterstation\n\nDie Wetterstation soll aus insgesamt drei Stationen zusammengesetzt sein:\n\n1. Die Seonsoranlage gesteuert durch einen Raspberry Pi Pico 2WH, verbunden mit einem Temperatur- und Feuchtigkeitssensor (DHT22) und ggf. mit einem Feinstaubsensor (HM3301).\n2. Ein Server, der die Daten der Sensoranlage empfängt und anschließend in einer Datenbank speichert.\n3. Eine Website, die die vom Server abgelegten Daten nach benutzerdefinierten Vorgaben sortiert ausgibt.\n\n## Client\n\nDer Client (die Sensoranlage) nimmt die Daten aus den Sensoren auf und verschickt den Datensatz gebündelt an den Server.\n\n```json\n{\n    \"datetime\": \"2025-08-20 12:00:00\",\n    \"temperature\": 23.4,\n    \"humidity\": 45.6\n}\n```\n\nEs bieten sich zwei mögliche Programmiersprachen für den Client an: Python und Rust. Nachfolgend werden Ideen für beide Varianten exerziert.\n\n### Python\n\nMit Python wäre man am besten mit [MicroPython](https://micropython.org) beraten. Alles weitere soll hier noch hinzugefügt werden. Der Chip läuft und sendet fleißig Daten an alle Adressen, die man ihm gibt, Python war keine Kunst.\n\n#### HAL-Operations\n\nMit `machine` ist das eine Kleinigkeit, alles läuft super stabil und einfach (!).\n\n#### DHT22\n\nDHT als Sensorgruppe kommuniziert über das 1-Wire-Protokoll mit dem Chip und entsprechend einfach ist das Auslesen über eine standardisierte Bibliothek.\n\n#### HTTP Connection\n\nÜber `network` und `socket` erfolgt das Versenden des `POST`-Requests ganz leicht.\n\n#### `.env`-Handling\n\n`pip` hat hier sicher ein passendes Modul, ein einfacher Parser ist hierfür aber auch schnell gebaut und *embedded* vielleicht sogar die bessere Wahl. Fraglich ist nur, wie das ganze dann auf dem Pico abgelegt werden kann.\n\n### Rust\n\n[`embassy-rp`](https://docs.embassy.dev/embassy-rp/git/rp2040/index.html) scheint gut zu funktionieren. Das ist wirklich eine umfangreiche Bibliothek, die mir hoffentlich das meiste abnehmen kann.\n\n[Murrays Embedded Rust Tutorialreihe](https://murraytodd.medium.com/list/murrays-raspberry-pi-pico-w-embedded-rust-series-fac1064d4d03) sollte mich hoffentlich bei allen Dingen um ein gutes Stück weiter bringen.\n\n- Die LED ist ausschließlich via CWY43 (dem Netzwerkchip) ansprechbar, nicht via GPIO25 o.Ä., einfaches Debugging mittels Lämpchen wird also schwieriger, evtl. über PIO (*programmable input/output*).\n\nDas [Embassy-Buch über Zeit](https://embassy.dev/book/) ist sicher hilfreich beim Scheduling der einzelnen Programmschritte im Loop.\n\n##### Echtzeituhr\n\nDer Pico hat keine eingebaute CMOS-Batterie o. Ä. und ist deshalb explizit darauf angewiesen, mit einer aktuellen Uhrzeit versorgt zu werden.\n\n##### HAL-Operations\n\nAls erstes ist der Zugriff auf grundsätzliche Chip-Funktionen notwendig (I2C (evtl. für Feinstaubsensor), GPIO usw.). Rust hat hierfür [`rp235x_hal`](https://docs.rs/rp235x_hal/latest/rp235x_hal).\n\n#### DHT22\n\nDer Temperatur- und Feuchtesensor sollte eigentlich über ein standardisiertes Interface ansprechbar sein, weswegen hier auch ein Community-betreutes Paket ausreichen sollte: [`embedded-dht-rs`](https://github.com/rust-dd/embedded-dht-rs).\n\nHier ist für alle Chips dieser Art Unterstützung vorhanden, außerdem ist die letzte Version verhältnismäßig jung.\n\n#### HTTP Connection\n\nHier brauche ich noch ein Paket, das mir erlaubt, bei erfolgreich gelesenen Sensordaten eine einfache `GET`-Request abzuschicken und bei erhaltener Response im Fehlerfall kurz blau zu leuchten. [`http`](https://docs.rs/http/latest/http) kann das.\n\n#### `.env`-Handling\n\nDaten für die Verbindung zum Router sollten in einer `.env`-Datei ausgelagert sein. Rust hat dafür [`env_file_reader`](https://github.com/jofas/env_file_reader).\n\nEs scheint aber, dass Rust hier auch [bessere Voraussetzungen](https://murraytodd.medium.com/rust-networking-with-the-raspberry-pi-pico-w-00238415954b) mit `Cargo.toml` schafft.\n\n#### Know-how\n\nZuerst muss ich rausfinden, wie ich mit Rust so klar komme. Da fehlt mir schon noch einiges. Gerade die Frage mit dem Errorhandling und optionalen Funktionsabläufen muss ich mir natürlich sehr genau anschauen, wenn ich ein System bauen will, das nicht nach einem Nachmittag in irgendeinen Fehler läuft und keine Daten mehr liefert.\n\n## Server\n\nAls Server habe ich mir eigentlich schon überlegt, alles in Python zu schreiben. [FastAPI](https://fastapi.tiangolo.com) sollte mir da eigentlich gute Dienste erweisen können. Gerade die CRUD-Operationen für welche Datenbank auch immer sollte damit eigentlich ein Selbstläufer sein (oder zumindest wesentlich viel einfacher).\n\nDie offensichtliche Alternative wäre womöglich dann NodeJS. Aber ob mir das so taugt, das Handling, nehme ich an, ist in Python dann doch schon ziemlich angenehm.\n\nUm den Server zu testen, sind folgendes nützliche `cURL`-Befehle:\n\n```shell\n# GET\ncurl pidog.local:8000 -X GET\n# PUT\ncurl pidog.local:8000 -X PUT -H \"X-Authorization: ***\" -H \"Content-Type: application/json\" -d '{\"datetime\":\"2025-08-26\",\"temperature\":25.6,\"humidity\":48.7}'\n```\n\n### Weitere Entwicklungen\n\nFür die Ausgabe von vielen Werten über einen längeren Zeitraum wird es eventuell nötig sein, einige Werte zu überspringen (der Sensor schickt jeden Tag etwa 100 Werte an den Server).\n\nEine Möglichkeit bestünde darin, dass das Frontend einfach alle Werte für den gefragten Zeitraum anfordert und selbst sortiert. Für kleinere bis mittlere Datenmengen wäre das auf jeden Fall ein probates Mittel. Für große Datenmenge stellen sich allerdings zwei Fragen:\n\n1. Warum sollte diese Arbeit der Client überhaupt machen? -\u003e Warum nicht die Datenbank?\n2. Warum sollte ein beträchtlicher Anteil an unnötigen Daten versandt werden? Wenn nur jeder zehnte Eintrag für das Frontend relevant ist, warum dann überhaupt mitschicken?\n\n[Stackoverlow](https://stackoverflow.com/questions/4799816/return-row-of-every-nth-record) hat für diesen Fall einige interessante Ideen, vielleicht lassen sich die auf Ebene der Datenbankabfrage einpflegen und mit einem entsprechenden API-Befehl verknüpfen. So sollte die Belastung auch für den Server hoffentlich möglichst gering sein:\n\n```sql\nSELECT *\nFROM\n(\n    SELECT *, ROW_NUMBER() OVER (ORDER BY datetime) AS rownum\n    FROM messdaten\n) AS t\nWHERE t.rownum % quota = 0\nORDER BY datetime\n```\n\n## Frontend\n\nMit [ChartJS](https://www.chartjs.org) ließen sich bestimmt sehr schicke erste Darstellungen bauen. Einzig, man muss vermutlich mit React oder vielleicht Svelte arbeiten, wenn man alles schön integrieren möchte, ansonsten wirkt das arg kompliziert. Darüber hinaus sollte das aber ganz gut funktionieren. Die Daten sollten ja immerhin kein Problem sein mit der aktuellen Pipeline.\n\nEine schöne Website ließe sich mit React auch mit [shadcn/ui](https://ui.shadcn.com/) bauen. Das sollte auch die Gestaltung in schnellen Zügen vorankommen lassen. ChartJS (s. o.) hat sicherlich den Vorteil, dass man kein monströses Framework drumherum bauen muss, das wäre vielleicht ganz fein. Es sei denn, [`\u003cRecharts /\u003e`](https://recharts.org/) hat an der Stelle vernünftige Aktionen parat, sodass auch viele Datenpunkte schön dargestellt werden.\n\nFür's erste ist man bei ChartJS gut aufgehoben. Aber gerade mit Blick auf eine Zukunft, in der phasenweise keine Werte aufgenommen werden (können), wäre eine fortgeschrittenere Darstellung angebracht. D3 hat dafür [eine Lösung für unterbrochene](https://observablehq.com/@d3/line-chart-missing-data/2) und für [mehrere gleichzeitige Liniendiagramme](https://observablehq.com/@d3/multi-line-chart/2).\n\n## Development\n\n### Client\n\n### Server\n\nDev-Server für FastAPI starten (mit Flag für Zugänglichkeit im lokalen Netzwerk):\n\n```shell\nuv run fastapi dev --host 0.0.0.0\n```\n\n### Frontend\n\n```shell\nnpm start. # startet den Testserver von PArcel\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flowfatprophet%2Fwetterstation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flowfatprophet%2Fwetterstation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flowfatprophet%2Fwetterstation/lists"}