{"id":839,"date":"2025-09-24T12:49:44","date_gmt":"2025-09-24T10:49:44","guid":{"rendered":"https:\/\/elv001.staging.360vier.net\/?p=839"},"modified":"2026-03-05T13:46:57","modified_gmt":"2026-03-05T12:46:57","slug":"virtuelle-instrumente-python-raspberrypi","status":"publish","type":"post","link":"https:\/\/de.elv.com\/elvjournal\/virtuelle-instrumente-python-raspberrypi\/","title":{"rendered":"Einstieg in Python (Teil 11): virtuelle Instrumente"},"content":{"rendered":"\n<p class=\"has-gray-light-color has-text-color has-link-color has-h-5-font-size wp-elements-a3dfde45cf5ffa7d806467ebd71ac600\"><strong>Einstieg in Python, Teil 11<\/strong><\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Virtuelle Instrumente<\/h1>\n\n\n\n<p><strong>In einer zunehmend digitalisierten Welt spielen virtuelle Instrumente eine immer wichtigere Rolle. In Forschung, Lehre und industriellen Anwendungen sind sie praktisch \u00fcberall im Einsatz. Anstelle teurer physikalischer Messger\u00e4te erm\u00f6glichen es virtuelle Instrumente, Signale zu simulieren, Daten zu erfassen, zu analysieren und visuell darzustellen \u2013 alles direkt auf einem Computer oder sogar auf einem kleinen System wie dem Raspberry Pi. Besonders attraktiv wird dieses Konzept durch die Programmiersprache Python, die durch ihre einfache Syntax und umfangreiche Bibliotheken ideale Voraussetzungen f\u00fcr die Entwicklung solcher Softwarel\u00f6sungen bietet. <\/strong><br><br><strong>Ob Oszilloskope, Spektrumanalysatoren oder Temperaturmonitore \u2013 mit Python lassen sich vielseitige virtuelle Instrumente erstellen, die nicht nur kosteng\u00fcnstig, sondern auch flexibel anpassbar sind. Dieser Artikel gibt einen praxisnahen Einstieg in die Welt der virtuellen Instrumente mit Python: von der grundlegenden Idee \u00fcber geeignete Bibliotheken wie Tkinter bis hin zu konkreten Umsetzungsbeispielen.<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Analoge Eingangssignale erfassen<\/h2>\n\n\n\n<p>Als leistungsf\u00e4higer Einplatinencomputer eignet sich der Raspberry Pi hervorragend f\u00fcr Mess- und Steuerungsaufgaben. Eine seiner wenigen Einschr\u00e4nkungen: Er verf\u00fcgt \u00fcber keine integrierten analogen Eing\u00e4nge. F\u00fcr Projekte, die analoge Signale \u2013 etwa von Sensoren, Potentiometern oder analogen Spannungsquellen \u2013 erfassen sollen, ist daher ein externer Analog-Digital-Wandler (ADC) notwendig.<br><br>Ein besonders kompakter und leicht zu integrierender ADC ist der <a href=\"https:\/\/www.microchip.com\/en-us\/product\/mcp3002\">MCP3002<\/a> von Microchip. Dieser 10-Bit-Konverter kommuniziert \u00fcber die SPI-Schnittstelle und bietet zwei analoge Eingangskan\u00e4le. Damit eignet er sich ideal f\u00fcr einfache Messaufgaben wie Spannungsmessung, Sensoranbindung oder Signalanalyse.<br><br>In Kombination mit Python und der <code>spidev<\/code>-Bibliothek l\u00e4sst sich der MCP3002 schnell in Betrieb nehmen. Die Messdaten k\u00f6nnen anschlie\u00dfend f\u00fcr weitere Anwendungen genutzt werden \u2013 etwa zur Visualisierung in einem virtuellen Oszilloskop, zur Datenaufzeichnung oder zur Steuerung von Aktoren.<br><br>Im Folgenden wird kurz erl\u00e4utert, wie der ADC am Raspberry Pi eingesetzt werden kann. Weitere Details dazu wurden bereits im <a href=\"https:\/\/de.elv.com\/p\/python-micropython-programmieren-lernen-fuer-einsteiger-erfassung-analoger-werte-P254207\/?itemId=254207\">Artikel \u201eErfassung analoger Werte\u201c in Teil 5 dieser Reihe<\/a> vorgestellt und k\u00f6nnen dort bei Bedarf nachgeschlagen werden.<br><br>Der MCP3002 erm\u00f6glicht mit seinen zwei Eingangskan\u00e4len die pr\u00e4zise Erfassung analoger Spannungen \u2013 z.\u202fB. von Temperatur-, Licht- oder Positionssensoren. Dank seines kleinen Geh\u00e4uses, niedrigen Stromverbrauchs und der einfachen Ansteuerung ist er ideal f\u00fcr kompakte und energieeffiziente Messsysteme. Die folgende Tabelle fasst die wichtigsten Daten des Bausteins zusammen:<\/p>\n\n\n\n<figure class=\"wp-block-table has-text-small-font-size\"><table class=\"has-fixed-layout\"><tbody><tr><td><strong>Aufl\u00f6sung<\/strong><\/td><td>10 Bit (Wertebereich: 0\u20131023)<\/td><\/tr><tr><td><strong>Eingangskan\u00e4le<\/strong><\/td><td>2 (CH0 und CH1)<\/td><\/tr><tr><td><strong>Schnittstelle<\/strong><\/td><td>SPI (bis zu 3,6\u202fMHz Taktfrequenz)<\/td><\/tr><tr><td><strong>Versorgungsspannung<\/strong><\/td><td>2,7\u20135,5 V<\/td><\/tr><tr><td><strong>Abtastrate<\/strong><\/td><td>bis ca. 200\u202fksps (kilo-samples per second)<\/td><\/tr><tr><td><strong>Typischer Stromverbrauch<\/strong><\/td><td>&lt; 1\u202fmA aktiv, &lt; 2\u202f\u00b5A im Stand-by<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>In <mark style=\"background-color:rgba(0, 0, 0, 0);color:#2769b2\" class=\"has-inline-color\">Bild 1<\/mark> und <mark style=\"background-color:rgba(0, 0, 0, 0);color:#2769b2\" class=\"has-inline-color\">Bild 2<\/mark> wird gezeigt, wie der Baustein mit dem Raspberry Pi verbunden wird.&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n\n\n\n<div class=\"wp-block-columns are-vertically-aligned-bottom is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-vertically-aligned-bottom is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1077\" height=\"1302\" src=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild01_MCP3002.jpg\" alt=\"Bild 1: MCP3002 am Raspberry Pi\" class=\"wp-image-861\" style=\"width:497px;height:auto\" srcset=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild01_MCP3002.jpg 1077w, https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild01_MCP3002-248x300.jpg 248w, https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild01_MCP3002-768x928.jpg 768w\" sizes=\"auto, (max-width: 1077px) 100vw, 1077px\" \/><figcaption class=\"wp-element-caption\">Bild 1: MCP3002 am Raspberry Pi<\/figcaption><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-vertically-aligned-bottom is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1077\" height=\"1302\" src=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild02_ADC-Anschluss.jpg\" alt=\"Bild 2: Aufbau zum ADC-Anschluss an den Raspberry Pi\" class=\"wp-image-862\" srcset=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild02_ADC-Anschluss.jpg 1077w, https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild02_ADC-Anschluss-248x300.jpg 248w, https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild02_ADC-Anschluss-768x928.jpg 768w\" sizes=\"auto, (max-width: 1077px) 100vw, 1077px\" \/><figcaption class=\"wp-element-caption\">Bild 2: Aufbau zum ADC-Anschluss an den Raspberry Pi<\/figcaption><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p>Die folgende Tabelle zeigt die Verbindungen im \u00dcberblick:<\/p>\n\n\n\n<figure class=\"wp-block-table has-text-small-font-size\"><table class=\"has-fixed-layout\"><tbody><tr><td colspan=\"3\"><strong>MCP3002 am Raspberry Pi<\/strong><\/td><\/tr><tr><td colspan=\"2\"><strong>MCP3002<\/strong><\/td><td><strong>Raspberry Pi<\/strong><\/td><\/tr><tr><td>CS&nbsp;<\/td><td>Pin 1<\/td><td>CS0 \u2013 GPIO 10<\/td><\/tr><tr><td>CH0&nbsp;<\/td><td>Pin 2<\/td><td>Analog Input<\/td><\/tr><tr><td>CH1<\/td><td>Pin 3<\/td><td>Analog Input<\/td><\/tr><tr><td>V<sub>SS<\/sub><\/td><td>Pin 4<\/td><td>GND<\/td><\/tr><tr><td>DIN<\/td><td>Pin 5<\/td><td>MOSI \u2013 GPIO 12<\/td><\/tr><tr><td>DOUT&nbsp;<\/td><td>Pin 6<\/td><td>MISO \u2013 GPIO 13<\/td><\/tr><tr><td>CLK<\/td><td>Pin 7<\/td><td>SCLK \u2013 GPIO 14<\/td><\/tr><tr><td>V<sub>DD<\/sub><\/td><td>Pin 8<\/td><td>3V3<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Das folgende Programm liest den MCP3002 aus und stellt die ADC-Counts sowie die zugeh\u00f6rigen Spannungswerte auf der Konsole dar (MCP3002_tst.py):<\/p>\n\n\n\n<pre class=\"wp-block-code has-black-background-color has-background\" style=\"padding-top:var(--wp--preset--spacing--20);padding-right:var(--wp--preset--spacing--20);padding-bottom:var(--wp--preset--spacing--20);padding-left:var(--wp--preset--spacing--20)\"><code>\nimport spidev\nimport time\n\n# SPI initialisieren\nspi = spidev.SpiDev()\nspi.open(0, 0)&nbsp; # Bus 0, Device 0 (CE0)\nspi.max_speed_hz = 1000000&nbsp; # 1 MHz\n\n# Referenzspannung (V_REF = 3.3V)\nV_REF = 3.3\n\n# Funktion zum Auslesen des MCP3002 (Kanal 0 oder 1)\ndef read_mcp3002(channel):\n&nbsp;&nbsp;&nbsp; if channel not in &#91;0, 1]:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; raise ValueError(\"Kanal muss 0 oder 1 sein\")\n&nbsp;&nbsp;&nbsp; # Startbit (1), Single-Ended (1), Kanal (0\/1), MSBF (1)\n&nbsp;&nbsp;&nbsp; data = spi.xfer2(&#91;0b01101000 | (channel &lt;&lt; 4), 0])\n&nbsp;&nbsp;&nbsp; # Ergebnis: 10-Bit-Wert aus den empfangenen Bytes\n&nbsp;&nbsp;&nbsp; adc_value = ((data&#91;0] &amp; 0x03) &lt;&lt; 8) | data&#91;1]\n&nbsp;&nbsp;&nbsp; return adc_value\n\n# Spannung berechnen\ndef calculate_voltage(adc_value):\n&nbsp;&nbsp;&nbsp; return (adc_value \/ 1023) * V_REF\n\n# Hauptprogramm\ntry:\n&nbsp;&nbsp;&nbsp; while True:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Lies ADC-Wert von Kanal 0\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adc_value = read_mcp3002(0)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Berechne Spannung\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; voltage = calculate_voltage(adc_value)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Ausgabe in der Konsole\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print(f\"ADC-Wert: {adc_value}, Spannung: {voltage:.2f} V\")\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; time.sleep(0.1)&nbsp; # Aktualisiere alle 100 ms\nexcept KeyboardInterrupt:\n&nbsp;&nbsp;&nbsp; print(\"\\nProgramm beendet.\")\nfinally:\n&nbsp;&nbsp;&nbsp; spi.close()\n<\/code><\/pre>\n\n\n\n<p>Durch Anschluss eines zweiten Potentiometers (an Ch1, Pin3) k\u00f6nnen auch beide Kan\u00e4le ausgelesen werden (MCP3002_dual.py):<\/p>\n\n\n\n<pre class=\"wp-block-code has-black-background-color has-background\" style=\"padding-top:var(--wp--preset--spacing--20);padding-right:var(--wp--preset--spacing--20);padding-bottom:var(--wp--preset--spacing--20);padding-left:var(--wp--preset--spacing--20)\"><code>\n<strong>import<\/strong> spidev\n<strong>import<\/strong> time\n\n# SPI initialisieren\nspi = spidev.SpiDev()\nspi.open(0, 0)&nbsp; # Bus 0, Device 0 (CE0)\nspi.max_speed_hz = 1000000&nbsp; # 1 MHz\n\n# Referenzspannung (V_REF = 3.3V)\nV_REF = 3.3\n\n# Funktion zum Auslesen des MCP3002 (Kanal 0 oder 1)\n<strong>def<\/strong> read_mcp3002(channel):\n&nbsp;&nbsp;&nbsp; <strong>if<\/strong> channel <strong>not<\/strong> <strong>in<\/strong> &#91;0, 1]:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>raise<\/strong> ValueError(\"Kanal muss 0 oder 1 sein\")\n&nbsp;&nbsp;&nbsp; # Startbit (1), Single-Ended (1), Kanal (0\/1), MSBF (1)\n&nbsp;&nbsp;&nbsp; data = spi.xfer2(&#91;0b01101000 | (channel &lt;&lt; 4), 0])\n&nbsp;&nbsp;&nbsp; # Ergebnis: 10-Bit-Wert aus den empfangenen Bytes\n&nbsp;&nbsp;&nbsp; adc_value = ((data&#91;0] &amp; 0x03) &lt;&lt; 8) | data&#91;1]\n&nbsp;&nbsp;&nbsp; <strong>return<\/strong> adc_value\n\n# Spannung berechnen\n<strong>def<\/strong> calculate_voltage(adc_value):\n&nbsp;&nbsp;&nbsp; <strong>return<\/strong> (adc_value \/ 1023) * V_REF\n\n# Hauptprogramm\n<strong>try<\/strong>:\n&nbsp;&nbsp;&nbsp; <strong>while<\/strong> True:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>for<\/strong> channel <strong>in<\/strong> &#91;0, 1]:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adc_value = read_mcp3002(channel)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; voltage = calculate_voltage(adc_value)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>print<\/strong>(f\"Kanal {channel}: ADC-Wert = {adc_value}, Spannung = {voltage:.2f} V\")\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>print<\/strong>(\"-\" * 40)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; time.sleep(0.5)&nbsp; # Aktualisiere alle 500 ms\n<strong>except<\/strong> KeyboardInterrupt:\n&nbsp;&nbsp;&nbsp; <strong>print<\/strong>(\"\\nProgramm beendet.\")\n<strong>finally<\/strong>:\n&nbsp;&nbsp;&nbsp; spi.close()\n<\/code><\/pre>\n\n\n\n<p>Die Ausgabe auf die Konsole sieht dann beispielsweise so aus<mark style=\"background-color:rgba(0, 0, 0, 0);color:#2769b2\" class=\"has-inline-color\"> (Bild 3)<\/mark>:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-style-bordered\"><img loading=\"lazy\" decoding=\"async\" width=\"345\" height=\"240\" src=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild03_ADC-Werte.jpg\" alt=\"Bild 3: ADC-Werte in der Shell\" class=\"wp-image-849\" srcset=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild03_ADC-Werte.jpg 345w, https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild03_ADC-Werte-300x209.jpg 300w\" sizes=\"auto, (max-width: 345px) 100vw, 345px\" \/><figcaption class=\"wp-element-caption\">Bild 3: ADC-Werte in der Shell<\/figcaption><\/figure>\n\n\n\n<div style=\"height:24px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Grafische Messwertdarstellung<\/h2>\n\n\n\n<p>Nachdem nun analoge Messwerte erfasst werden k\u00f6nnen, sollen diese im n\u00e4chsten Schritt auf virtuellen Instrumenten dargestellt werden. Eine der einfachsten M\u00f6glichkeiten hierf\u00fcr sind sogenannte Bargraphanzeigen, auch als Balkendiagramme bekannt. Trotz ihrer Einfachheit bieten Balkendiagramme eine Reihe von Vorteilen, insbesondere wenn es darum geht, Daten klar und leicht verst\u00e4ndlich darzustellen. Die Hauptvorteile dieser Darstellungsvarianten sind:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u00dcbersichtlichkeit<\/strong>: Sie machen Unterschiede zwischen Daten schnell sichtbar, da die L\u00e4nge der Balken direkt vergleichbar ist<\/li>\n\n\n\n<li><strong>Einfache Interpretation<\/strong>: Selbst ohne tiefgehende Kenntnisse in Statistik kann man die Informationen schnell erfassen<\/li>\n\n\n\n<li><strong>Flexibilit\u00e4t<\/strong>: Sie eignen sich sowohl f\u00fcr absolute Werte als auch f\u00fcr Verh\u00e4ltnisse<\/li>\n\n\n\n<li><strong>Visuelle Wirkung<\/strong>: Farben und Anordnung k\u00f6nnen genutzt werden, um Muster oder Trends hervorzuheben<\/li>\n\n\n\n<li><strong>Geringer Platzverbrauch<\/strong>: Sie k\u00f6nnen sowohl horizontal als auch vertikal gestaltet werden, je nachdem, was f\u00fcr die Darstellung am sinnvollsten ist<\/li>\n<\/ul>\n\n\n\n<p>Das folgende Programm stellt die beiden ADC-Kan\u00e4le in Form von vertikalen Balken dar (MCP3002_dualBargraph.py). Die bereits bekannten Programmteile wurden im Folgenden weggelassen; der vollst\u00e4ndige Code findet sich im Downloadpaket.<\/p>\n\n\n\n<pre class=\"wp-block-code has-black-background-color has-background\" style=\"padding-top:var(--wp--preset--spacing--20);padding-right:var(--wp--preset--spacing--20);padding-bottom:var(--wp--preset--spacing--20);padding-left:var(--wp--preset--spacing--20)\"><code>\n<strong>import<\/strong> spidev\n<strong>import<\/strong> tkinter <strong>as<\/strong> tk\n\n&#91;...]\n\nroot = tk.Tk()\nroot.title(\"MCP3002 Bargraphanzeige\")\n\ncanvas_width = 300; canvas_height = 200; bar_width = 100; bar_spacing = 110\ncanvas = tk.Canvas(root, width=canvas_width, height=canvas_height, bg='white')\ncanvas.pack()\nbar0 = canvas.create_rectangle(50, canvas_height, 50 + bar_width, canvas_height, fill=\"green\")\nbar1 = canvas.create_rectangle(50 + bar_spacing, canvas_height, 50 + bar_spacing + bar_width, canvas_height, fill=\"blue\")\nlabel0 = canvas.create_text(100, canvas_height - 5, text=\"CH0\", font=(\"Arial\", 10))\nlabel1 = canvas.create_text(100 + bar_spacing, canvas_height - 5, text=\"CH1\", font=(\"Arial\", 10))\nvalue_text0 = canvas.create_text(100, 10, text=\"\", font=(\"Arial\", 12, \"bold\"))\nvalue_text1 = canvas.create_text(100 + bar_spacing, 10, text=\"\", font=(\"Arial\", 12, \"bold\"))\n\n<strong>def<\/strong> update_bars():\n&nbsp;&nbsp;&nbsp; value0 = read_mcp3002(0); value1 = read_mcp3002(1)\n&nbsp;&nbsp;&nbsp; height0 = int((value0 \/ max_adc) * (canvas_height - 40))\n&nbsp;&nbsp;&nbsp; height1 = int((value1 \/ max_adc) * (canvas_height - 40))\n&nbsp;&nbsp;&nbsp; canvas.coords(bar0, 50, canvas_height - height0 - 20, 50 + bar_width, canvas_height - 20)\n&nbsp;&nbsp;&nbsp; canvas.coords(bar1, 50 + bar_spacing, canvas_height - height1 - 20, 50 + bar_spacing + bar_width, canvas_height - 20)\n&nbsp;&nbsp;&nbsp; voltage0 = value0 * V_REF \/ max_adc; voltage1 = value1 * V_REF \/ max_adc\n&nbsp;&nbsp;&nbsp; canvas.coords(value_text0, 100, canvas_height - height0 - 30)\n&nbsp;&nbsp;&nbsp; canvas.itemconfig(value_text0, text=f\"{voltage0:.2f} V\")\n&nbsp;&nbsp;&nbsp; canvas.coords(value_text1, 100 + bar_spacing, canvas_height - height1 - 30)\n&nbsp;&nbsp;&nbsp; canvas.itemconfig(value_text1, text=f\"{voltage1:.2f} V\")\n&nbsp;&nbsp;&nbsp; root.after(200, update_bars)\n\nupdate_bars()\nroot.mainloop()\nspi.close()\n<\/code><\/pre>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<p>Nach dem Start des Programms erscheinen die aktuellen Spannungswerte beider ADC-Kan\u00e4le in jeweils einer eigenen Balkendarstellung <mark style=\"background-color:rgba(0, 0, 0, 0);color:#2769b2\" class=\"has-inline-color\">(Bild 4)<\/mark>. \u00dcber den Balken werden zus\u00e4tzlich die exakten Werte in numerischer Form ausgegeben.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full is-style-bordered\"><img loading=\"lazy\" decoding=\"async\" width=\"306\" height=\"228\" src=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild04_bargraphanzeige.jpg\" alt=\"Bild 4: Bargraphanzeige der ADC-Werte\" class=\"wp-image-850\" srcset=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild04_bargraphanzeige.jpg 306w, https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild04_bargraphanzeige-300x224.jpg 300w\" sizes=\"auto, (max-width: 306px) 100vw, 306px\" \/><figcaption class=\"wp-element-caption\">Bild 4: Bargraphanzeige der ADC-Werte<\/figcaption><\/figure>\n<\/div>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Virtuelle Instrumente in allen Formen und Farben<\/h2>\n\n\n\n<p>Rundinstrumente, wie sie h\u00e4ufig in Fahrzeugen, Maschinen und Uhren verwendet werden, bieten gegen\u00fcber Bargraphanzeigen einige praktische Vorteile:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Schnelle Ablesbarkeit<\/strong>: Der Zeiger zeigt intuitiv auf den Wert, wodurch Informationen leicht erfasst werden k\u00f6nnen<\/li>\n\n\n\n<li><strong>Gute Wahrnehmung bei Bewegung<\/strong>: Besonders in Autos oder Flugzeugen ist es einfacher, Ver\u00e4nderungen eines Zeigers zu erfassen als kleine digitale Zahlen<\/li>\n\n\n\n<li><strong>\u00c4sthetik und Design<\/strong>: Runde Anzeigen wirken oft klassisch und hochwertig, weshalb sie in vielen Premium-Produkten eingesetzt werden<\/li>\n\n\n\n<li><strong>Einfache Skalierung<\/strong>: Die Kreisform erm\u00f6glicht eine nat\u00fcrliche Verteilung von Skalenwerten, die in einem Blickfeld erfassbar sind<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:66.66%\">\n<p>Auch Rundinstrumente <mark style=\"background-color:rgba(0, 0, 0, 0);color:#2769b2\" class=\"has-inline-color\">(Bild 5)<\/mark> k\u00f6nnen relativ einfach in der virtuellen Welt dargestellt werden, wenngleich ihre Programmierung etwas aufwendiger ist als die Darstellung von Balkendiagrammen. Das folgende Programm (MCP3002_VirtualAnalog.py) zeigt die am ADC-Kanal 0 anliegende Spannung in einem Rundinstrument an:<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:33.33%\">\n<figure class=\"wp-block-image size-full is-style-bordered\"><img loading=\"lazy\" decoding=\"async\" width=\"404\" height=\"475\" src=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild05_rundinstrument.jpg\" alt=\"Bild 5: Rundinstrument f\u00fcr den Raspberry Pi\" class=\"wp-image-851\" srcset=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild05_rundinstrument.jpg 404w, https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild05_rundinstrument-255x300.jpg 255w\" sizes=\"auto, (max-width: 404px) 100vw, 404px\" \/><figcaption class=\"wp-element-caption\">Bild 5: Rundinstrument f\u00fcr den Raspberry Pi<\/figcaption><\/figure>\n<\/div>\n<\/div>\n\n\n\n<pre class=\"wp-block-code has-black-background-color has-background\" style=\"padding-top:var(--wp--preset--spacing--20);padding-right:var(--wp--preset--spacing--20);padding-bottom:var(--wp--preset--spacing--20);padding-left:var(--wp--preset--spacing--20)\"><code>\n<strong>import spidev, time, math, time<\/strong>\n<strong>import<\/strong> tkinter <strong>as<\/strong> tk\n<strong>from<\/strong> threading <strong>import<\/strong> Thread\n\n&#91;...]\n\n<strong>class<\/strong> AnalogInstrument(tk.Tk):\n&nbsp; <strong>def<\/strong> __init__(self):\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super().__init__()\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.title(\"MCP3002 Voltmeter\")\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.geometry(\"400x450\")\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas = tk.Canvas(self, width=400, height=450, bg=\"#000000\")\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas.pack()\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas.create_oval(50, 50, 350, 350, outline=\"#00008B\", fill=\"#00008B\", width=2)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>for<\/strong> i <strong>in<\/strong> range(0, 271, 27):\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; angle = math.radians(i - 135 + 270)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x1 = 200 + math.cos(angle) * 120\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; y1 = 200 + math.sin(angle) * 120\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x2 = 200 + math.cos(angle) * 140\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; y2 = 200 + math.sin(angle) * 140\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas.create_line(x1, y1, x2, y2, fill=\"#00FF00\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label_x = 200 + math.cos(angle) * 170\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &nbsp;label_y = 200 + math.sin(angle) * 170\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label_value = round(i * 5.0 \/ 270, 2)&nbsp; # Spannung berechnen\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas.create_text(label_x, label_y, text=str(label_value), font=(\"Arial\", 16), fill=\"#00FF00\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.pointer = self.canvas.create_line(200, 200, 200, 80, fill=\"#FF4500\", width=4)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  self.voltage_label = self.canvas.create_text(200, 400, text=\"Spannung: 0 V\", font=(\"Arial\", 20), fill=\"#00FF00\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.running = True\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.thread = Thread(target=self.update_instrument)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.thread.daemon = True\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.thread.start()\n\n&nbsp;&nbsp;&nbsp; <strong>def<\/strong> update_instrument(self):\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>while<\/strong> self.running:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>try<\/strong>:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; voltage = read_mcp3002(0)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; angle = (voltage \/ 5.0) * 270 - 135 + 270\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; angle_rad = math.radians(angle)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x = 200 + math.cos(angle_rad) * 110\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; y = 200 + math.sin(angle_rad) * 110\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas.coords(self.pointer, 200, 200, x, y)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas.itemconfig(self.voltage_label, text=f\"Spannung: {voltage:.2f} V\")\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; time.sleep(0.1)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>except<\/strong> Exception <strong>as<\/strong> e:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>print<\/strong>(f\"Fehler: {e}\")\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>break<\/strong>\n\n&nbsp;&nbsp;&nbsp; <strong>def<\/strong> destroy(self):\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.running = False\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spi.close()\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super().destroy()\n\n# Hauptprogramm\napp = AnalogInstrument()\napp.mainloop()\n<\/code><\/pre>\n\n\n\n<p>Das Programm emuliert ein einfaches analoges Voltmeter, das die Messwerte eines MCP3002-AD-Wandlers grafisch als Rundinstrumenten-Anzeige darstellt.<br>Die Klasse AnalogInstrument erstellt eine grafische Oberfl\u00e4che mit Tkinter. Das Voltmeter besteht dabei aus den folgenden Elementen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ziffernblatt mit Skala (0\u20135 V)<\/li>\n\n\n\n<li>Zeiger<\/li>\n\n\n\n<li>Numerische Anzeige der Spannung<\/li>\n<\/ul>\n\n\n\n<p>F\u00fcr eine fl\u00fcssige Darstellung wird ein eigener Thread (self.thread) gestartet, um die Spannung kontinuierlich zu messen und die Anzeige zu aktualisieren. Der Zeiger wird dann entsprechend der gemessenen Spannung dargestellt. Die Spannung wird in einen Winkel (0\u2013270\u00b0) umgerechnet, und die Koordinaten des Zeigers werden mit self.canvas.coords() berechnet. Das Programm l\u00e4uft in einer Endlosschleife, bis die GUI geschlossen wird. Danach wird die SPI-Schnittstelle sauber beendet.<\/p>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<p>Man kann sogar noch einen Schritt weiter gehen und ein klassisches Analoginstrument virtualisieren. <mark style=\"background-color:rgba(0, 0, 0, 0);color:#2769b2\" class=\"has-inline-color\">Bild 6<\/mark> zeigt eine entsprechende Darstellung. Da das Programm hierf\u00fcr bereits relativ umfangreich ist, soll es hier nicht im Detail wiedergegeben und diskutiert werden. Der vollst\u00e4ndige Code findet sich aber im Downloadpaket.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-full is-style-bordered\"><img loading=\"lazy\" decoding=\"async\" width=\"303\" height=\"245\" src=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild06_voltmeter.jpg\" alt=\"Bild 6: Virtuelles analoges Voltmeter\" class=\"wp-image-852\" srcset=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild06_voltmeter.jpg 303w, https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild06_voltmeter-300x243.jpg 300w\" sizes=\"auto, (max-width: 303px) 100vw, 303px\" \/><figcaption class=\"wp-element-caption\">Bild 6: Virtuelles analoges Voltmeter<\/figcaption><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p>Ein besonderer Vorteil bei virtuellen Instrumenten ist, dass der exakte Wert zus\u00e4tzlich auch digital dargestellt werden kann. Damit werden Ablesefehler nahezu ausgeschlossen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wetter- und Klimadaten aus dem Internet<\/h2>\n\n\n\n<p>Auch ohne AD-Wandler k\u00f6nnen virtuelle Instrumente nutzbringend eingesetzt werden. Eine M\u00f6glichkeit ist die Verwendung von aktuellen Wetterdaten aus dem Internet. Damit lassen sich individuelle Klimastationen aufbauen, ohne dass aufwendige Sensoren auf der Anwenderseite erforderlich sind. <br><br>Die Wetterdaten k\u00f6nnen von OpenWeatherMap auf den Raspberry Pi geladen werden, indem eine API genutzt wird. Hier sind die grundlegenden Schritte:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Auf OpenWeatherMap registrieren und einen kostenlosen API-Schl\u00fcssel erstellen<\/li>\n\n\n\n<li><strong>requests<\/strong> installieren, um HTTP-Anfragen zu senden:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>pip install requests\n<\/code><\/pre>\n\n\n\n<p>Dann k\u00f6nnen verschiedene Wetterdaten ausgelesen und dargestellt werden (OpenWeatherMap_tst.py)<\/p>\n\n\n\n<pre class=\"wp-block-code has-black-background-color has-background\" style=\"padding-top:var(--wp--preset--spacing--20);padding-right:var(--wp--preset--spacing--20);padding-bottom:var(--wp--preset--spacing--20);padding-left:var(--wp--preset--spacing--20)\"><code>\nimport requests\n\n# API-Schl\u00fcssel und Stadt\nAPI_KEY = \"12345678901234567890123456789012\"\nSTADT = \"Leer\"\nURL = f\"http:\/\/api.openweathermap.org\/data\/2.5\/weather?q={STADT}&amp;appid={API_KEY}&amp;units=metric\"\n\n# Wetterdaten abrufen\nresponse = requests.get(URL)\nwetterdaten = response.json()\n\n# Daten extrahieren\ntemperatur = f\"{wetterdaten&#91;'main']&#91;'temp']} \u00b0C\"\nluftfeuchtigkeit = f\"{wetterdaten&#91;'main']&#91;'humidity']} %\"\nluftdruck = f\"{wetterdaten&#91;'main']&#91;'pressure']} hPa\"\nwindgeschwindigkeit = f\"{wetterdaten&#91;'wind']&#91;'speed']} m\/s\"\nwetterlage = wetterdaten&#91;'weather']&#91;0]&#91;'description']\n\n# Formatierte Ausgabe\nprint(\"=\"*30)\nprint(f\"{'Parameter':&lt;20}{'Wert':&lt;10}\")\nprint(\"=\"*30)\nprint(f\"{'Temperatur':&lt;20}{temperatur:&lt;10}\")\nprint(f\"{'Luftfeuchtigkeit':&lt;20}{luftfeuchtigkeit:&lt;10}\")\nprint(f\"{'Luftdruck':&lt;20}{luftdruck:&lt;10}\")\nprint(f\"{'Windgeschwindigkeit':&lt;20}{windgeschwindigkeit:&lt;10}\")\nprint(f\"{'Wetterlage':&lt;20}{wetterlage:&lt;10}\")\nprint(\"=\"*30)\n<\/code><\/pre>\n\n\n\n<p><mark style=\"background-color:rgba(0, 0, 0, 0);color:#2769b2\" class=\"has-inline-color\">Bild 7<\/mark> zeigt ein beispielhaftes Ergebnis dieser Abfrage.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-style-bordered\"><img loading=\"lazy\" decoding=\"async\" width=\"296\" height=\"233\" src=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild07_klimadaten.jpg\" alt=\"Bild 7: Wetter und Klimadaten aus dem Internet\" class=\"wp-image-853\"\/><figcaption class=\"wp-element-caption\">Bild 7: Wetter und Klimadaten aus dem Internet<\/figcaption><\/figure>\n\n\n\n<p>Im Folgenden soll gezeigt werden, wie diese Daten f\u00fcr einer ansprechenden Wetterstation umgesetzt werden k\u00f6nnen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Umfangreiche virtuelle Klimastation<\/strong><\/h2>\n\n\n\n<p>Eine virtuelle Wetterstation auf dem Raspberry Pi bietet zahlreiche praktische Vorteile, die sie zu einer idealen L\u00f6sung f\u00fcr private und p\u00e4dagogische Zwecke machen. Der gr\u00f6\u00dfte Pluspunkt ist die Kosteneffizienz \u2013 im Gegensatz zu teuren professionellen Wetterstationen gen\u00fcgen hier ein preiswerter Raspberry Pi und ein einfaches Display. Auf kostspielige Spezialsensoren kann verzichtet werden, da die Wetterdaten direkt von der OpenWeatherMap API bezogen werden.<br><br>Die Station ist platzsparend und mobil einsetzbar, sei es in der Wohnung, im B\u00fcro oder in einem Klassenzimmer. Anders als bei analogen Wetterstationen gibt es keine mechanischen Bauteile, die verschlei\u00dfen k\u00f6nnten, was die Wartung vereinfacht. Updates erfolgen rein softwarebasiert, und Messbereiche lassen sich problemlos per Code anpassen, ohne dass Hardware ausgetauscht werden m\u00fcsste.<br><br>Die Erweiterbarkeit ist ebenfalls ein gro\u00dfer Vorteil: Nutzer k\u00f6nnen die Anzeige individuell anpassen, zus\u00e4tzliche Wetterparameter einbinden oder die Visualisierung f\u00fcr verschiedene Displaygr\u00f6\u00dfen skalieren. Zudem lassen sich \u201eSmart Features\u201c wie<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>automatische Datenaktualisierungen,<\/li>\n\n\n\n<li>historische Datenspeicherung oder<\/li>\n\n\n\n<li>Warnmeldungen bei Extremwerten<\/li>\n<\/ul>\n\n\n\n<p>implementieren.<br><br>Die Wetterstation (OpenWeatherMap_graph.py) zeigt die aktuellen Wetterdaten und Vorhersagen f\u00fcr einen konfigurierbaren Ort (z. B. Leer, Hamburg oder M\u00fcnchen) an. Das Programm nutzt die OpenWeatherMap API, um Echtzeit-Wetterinformationen abzurufen und in einer ansprechenden Visualisierung darzustellen<strong>.<\/strong> Die Anwendung besteht aus vier Hauptinstrumenten:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Thermometer mit einem Messbereich von -20 \u00b0C bis +40 \u00b0C,<\/li>\n\n\n\n<li>Hygrometer f\u00fcr die Luftfeuchtigkeit von 0 bis 100 %,<\/li>\n\n\n\n<li>Barometer f\u00fcr den Luftdruck (950\u20131050 hPa)<\/li>\n\n\n\n<li>Windrose sowie Bargraphanzeige zur Darstellung von Windrichtung und -geschwindigkeit (0\u2013100 km\/h).<\/li>\n<\/ul>\n\n\n\n<p>Da das Programm recht umfangreich ist, soll es hier nicht vollst\u00e4ndig angegeben werden (die komplette Version findet sich im Downloadpaket). Vielmehr sollen exemplarisch einige wichtige Details n\u00e4her erl\u00e4utert werden. <br><br>Das Dashboard liefert das Grundger\u00fcst f\u00fcr die grafische Anzeige:<\/p>\n\n\n\n<pre class=\"wp-block-code has-black-background-color has-background\" style=\"padding-top:var(--wp--preset--spacing--20);padding-right:var(--wp--preset--spacing--20);padding-bottom:var(--wp--preset--spacing--20);padding-left:var(--wp--preset--spacing--20)\"><code>\nclass WeatherDashboard(tk.Tk):\n&nbsp;&nbsp;&nbsp; def __init__(self):\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super().__init__()\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.title(\"Virtuelle Wetterstation\")\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.geometry(\"1250x800\")\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.config(bg=BackroundColor)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; main_frame = tk.Frame(self, bg=BackroundColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; main_frame.pack(expand=True, fill=tk.BOTH, padx=20, pady=20)\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; left_frame = tk.Frame(main_frame, bg=BackroundColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; left_frame.grid(row=0, column=0, padx=10, pady=10, sticky=\"n\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; center_frame = tk.Frame(main_frame, bg=BackroundColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; center_frame.grid(row=0, column=1, padx=10, pady=10, sticky=\"n\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; right_frame = tk.Frame(main_frame, bg=BackroundColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; right_frame.grid(row=0, column=2, padx=10, pady=10, sticky=\"n\")\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Linke Spalte\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.weather_icon_frame = tk.Frame(left_frame, bg=BackroundColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.weather_icon_frame.pack()\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.weather_icon_label = tk.Label(self.weather_icon_frame, bg=BackroundColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.weather_icon_label.pack()\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.weather_desc_label = tk.Label(left_frame, text=\"Aktuelles Wetter: -\", font=(\"Arial\", 14, \"bold\"), bg=BackroundColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.weather_desc_label.pack(pady=5)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n        self.frame_temp = tk.Frame(left_frame, bg=BackroundColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.frame_temp.pack(pady=20)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.temp_label = tk.Label(self.frame_temp, text=\"Temperatur: 0\u00b0C\", font=(\"Arial\", 14, \"bold\"), bg=BackroundColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.temp_label.pack()\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas_temp = tk.Canvas(self.frame_temp, width=200, height=400, bg=InstrumentBackground, highlightthickness=0)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas_temp.pack()\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Mittlere Spalte\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.frame_baro = tk.Frame(center_frame, bg=BackroundColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.frame_baro.pack()\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.baro_label = tk.Label(self.frame_baro, text=\"Luftdruck: 0 hPa\", font=(\"Arial\", 14, \"bold\"), bg=BackroundColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.baro_label.pack()\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas_baro = tk.Canvas(self.frame_baro, width=300, height=300, bg=InstrumentBackground, highlightthickness=0)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas_baro.pack()\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \n        self.frame_wind = tk.Frame(center_frame, bg=BackroundColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.frame_wind.pack(pady=20)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.wind_label = tk.Label(self.frame_wind, text=\"Wind: N (0\u00b0) - 0 km\/h\", font=(\"Arial\", 14, \"bold\"), bg=BackroundColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.wind_label.pack()\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas_wind = tk.Canvas(self.frame_wind, width=300, height=300, bg=InstrumentBackground, highlightthickness=0)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas_wind.pack()\n\n&#91;...]\n<\/code><\/pre>\n\n\n\n<p>Das Thermometer wird als stilisierte Quecksilbers\u00e4ule angezeigt:<\/p>\n\n\n\n<pre class=\"wp-block-code has-black-background-color has-background\" style=\"padding-top:var(--wp--preset--spacing--20);padding-right:var(--wp--preset--spacing--20);padding-bottom:var(--wp--preset--spacing--20);padding-left:var(--wp--preset--spacing--20)\"><code>\ndef draw_thermometer(self):\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas_temp.create_rectangle(80, 30, 120, 350, outline=\"black\", width=2)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas_temp.create_oval(80, 330, 120, 390, outline=\"black\", width=2, fill=\"red\")\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for i in range(-20, 41, 5):\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; y = 350 - ((i + 20) * 5)\n&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.canvas_temp.create_line(120, y, 140, y, fill=\"black\", width=2)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas_temp.create_text(150, y, text=f\"{i}\u00b0C\", font=(\"Arial\", 10), anchor=\"w\", fill=\"blue\")\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.mercury = self.canvas_temp.create_rectangle(81, 350, 119, 350, fill=\"red\")\n<\/code><\/pre>\n\n\n\n<p>Luftdruckanzeige und Hygrometer bestehen aus einem Rundinstrument:<\/p>\n\n\n\n<pre class=\"wp-block-code has-black-background-color has-background\" style=\"padding-top:var(--wp--preset--spacing--20);padding-right:var(--wp--preset--spacing--20);padding-bottom:var(--wp--preset--spacing--20);padding-left:var(--wp--preset--spacing--20)\"><code>\ndef draw_hygrometer(self):\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas_humidity.create_oval(50, 50, 350, 350, outline=\"black\", width=1, fill=InstrumentColor)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for i in range(0, 101, 10):\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; angle = math.radians((i \/ 100) * 270 - 135 + 270)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x1 = 200 + math.cos(angle) * 120\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; y1 = 200 + math.sin(angle) * 120\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x2 = 200 + math.cos(angle) * 140\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; y2 = 200 + math.sin(angle) * 140\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;self.canvas_humidity.create_line(x1, y1, x2, y2, fill=\"blue\", width=2)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label_x = 200 + math.cos(angle) * 100\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label_y = 200 + math.sin(angle) * 100\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.canvas_humidity.create_text(label_x, label_y, text=f\"{i}%\", font=(\"Arial\", 12, \"bold\"), fill=\"blue\")\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.pointer = self.canvas_humidity.create_line(200, 200, 200, 80, fill=\"red\", width=4)\n<\/code><\/pre>\n\n\n\n<p>Die Wettervorhersage wird als f\u00fcnfzeiliger Text ausgegeben:<\/p>\n\n\n\n<pre class=\"wp-block-code has-black-background-color has-background\" style=\"padding-top:var(--wp--preset--spacing--20);padding-right:var(--wp--preset--spacing--20);padding-bottom:var(--wp--preset--spacing--20);padding-left:var(--wp--preset--spacing--20)\"><code>\ndef update_forecast(self, forecast_data):\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; weekdays_de = &#91;\"Mo\", \"Di\", \"Mi\", \"Do\", \"Fr\", \"Sa\", \"So\"]\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; daily_forecasts = {}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for forecast in forecast_data&#91;'list']:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; date = forecast&#91;'dt_txt'].split()&#91;0]\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if date not in daily_forecasts:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; daily_forecasts&#91;date] = &#91;]\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; daily_forecasts&#91;date].append(forecast)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; forecast_dates = sorted(daily_forecasts.keys())&#91;:5]\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for i, date in enumerate(forecast_dates):\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; day_forecast = None\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for forecast in daily_forecasts&#91;date]:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if forecast&#91;'dt_txt'].endswith(\"12:00:00\"):\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; day_forecast = forecast\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not day_forecast:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; day_forecast = daily_forecasts&#91;date]&#91;len(daily_forecasts&#91;date])\/\/2]\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;temp_max = max(f&#91;'main']&#91;'temp_max'] for f in daily_forecasts&#91;date])\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; temp_min = min(f&#91;'main']&#91;'temp_min'] for f in daily_forecasts&#91;date])\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; description = day_forecast&#91;'weather']&#91;0]&#91;'description'].capitalize()\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; weekday_num = time.strptime(date, \"%Y-%m-%d\").tm_wday\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; weekday = weekdays_de&#91;weekday_num]\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; forecast_text = (f\"{weekday} ({date&#91;8:10]}.{date&#91;5:7]}): \"\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f\"{description}, {day_forecast&#91;'main']&#91;'temp']:.1f}\u00b0C \"\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f\"(max {temp_max:.1f}\u00b0C, min {temp_min:.1f}\u00b0C), \"\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f\"Wind: {day_forecast&#91;'wind']&#91;'speed']*3.6:.1f} km\/h\")\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if i &lt; len(self.forecast_labels):\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.forecast_labels&#91;i].config(text=forecast_text)\n\n<\/code><\/pre>\n\n\n\n<p>Die Vorhersage erfolgt mit deutschen Wochentagen und gibt die erwartete Wetterentwicklung an.<br><br>Das Programm nutzt Tkinter f\u00fcr die GUI-Entwicklung und verwendet die Bibliotheken \u201erequests\u201c f\u00fcr den API-Zugriff, sowie \u201ethreading\u201c f\u00fcr die regelm\u00e4\u00dfige Aktualisierung der Daten im Hintergrund. Die Aktualisierung erfolgt alle zehn Minuten, bei Fehlern wird ein k\u00fcrzeres Intervall verwendet.<br><br>Besondere Merkmale sind die freie Farbgestaltung, die pr\u00e4zise Skalierung aller Anzeigeinstrumente und die deutschsprachige Oberfl\u00e4che. Die Windrose verf\u00fcgt \u00fcber einen stilisierten Zeiger, w\u00e4hrend das Barometer eine klare Druckanzeige mit skalierter Anzeige bietet. <br><br>Das Programm <mark style=\"background-color:rgba(0, 0, 0, 0);color:#2769b2\" class=\"has-inline-color\">(Bild 8)<\/mark> startet mit einem Fenster der Gr\u00f6\u00dfe 1250 x 800 Pixel und ist in drei Spalten unterteilt: Links befinden sich Thermometer und Wettergrafik, in der Mitte Barometer und Windrose, rechts Hygrometer, Windgeschwindigkeit und die f\u00fcnft\u00e4gige Vorhersage. Alle Instrumente sind klar beschriftet und zeigen die Werte sowohl grafisch als auch numerisch an.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-style-bordered\"><img loading=\"lazy\" decoding=\"async\" width=\"1254\" height=\"825\" src=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild08_virtuelle-klimastation.jpg\" alt=\"Bild 8: Virtuelle Klimastation\" class=\"wp-image-854\" srcset=\"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild08_virtuelle-klimastation.jpg 1254w, https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild08_virtuelle-klimastation-300x197.jpg 300w, https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Phyton11_Bild08_virtuelle-klimastation-768x505.jpg 768w\" sizes=\"auto, (max-width: 1254px) 100vw, 1254px\" \/><figcaption class=\"wp-element-caption\">Bild 8: Virtuelle Klimastation<\/figcaption><\/figure>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-group has-gray-lightest-100-background-color has-background is-layout-constrained wp-container-core-group-is-layout-ff778368 wp-block-group-is-layout-constrained\" style=\"padding-right:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--30)\">\n<h2 class=\"wp-block-heading\"><strong>Erg\u00e4nzungen und Anregungen<\/strong><\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Wie kann man Stromst\u00e4rken mit einem virtuellen Instrument anzeigen?<\/li>\n\n\n\n<li>Kann man die Instrumente nach <mark style=\"background-color:rgba(0, 0, 0, 0);color:#2769b2\" class=\"has-inline-color\">Bild 5<\/mark> oder <mark style=\"background-color:rgba(0, 0, 0, 0);color:#2769b2\" class=\"has-inline-color\">Bild 6<\/mark> auch mit Autoscaling-Funktionen versehen?<\/li>\n\n\n\n<li>K\u00f6nnte man auch reale Sensoren f\u00fcr Luftdruck und -feuchtigkeit auf virtuellen Analoguhr-Instrumenten ausgeben?\n<ul class=\"wp-block-list\">\n<li>Wie k\u00f6nnten diese Instrumente aussehen?<\/li>\n\n\n\n<li>Kann man die Instrumente auch durch animierte Grafiken darstellen?<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Wie kann man die Wetterstation um historische Verl\u00e4ufe von Temperatur, Feuchtigkeit oder Luftdruckwerten erg\u00e4nzen?<br><\/li>\n<\/ul>\n<\/div>\n\n\n\n<div style=\"height:40px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Zusammenfassung und Ausblick<\/h2>\n\n\n\n<p>In diesem Beitrag wurden die grafischen Darstellungsm\u00f6glichkeiten f\u00fcr virtuelle Instrumente ausf\u00fchrlich untersucht. Neben messtechnischen Anwendungen wie Analogvoltmetern wurde dabei auch eine vollst\u00e4ndige Klimastation implementiert. In den n\u00e4chsten Beitr\u00e4gen soll es hingegen wieder um reale Hardware-Instrumente in Form von Displays und Anzeigeeinheiten gehen. Diese k\u00f6nnen auf verschiedene Weise mit dem Raspberry Pi angesteuert werden. Auch hier stellt Python wieder eine Reihe n\u00fctzlicher Hilfsmittel zur Verf\u00fcgung. Im kommenden Blog-Beitrag soll dabei die Ansteuerung von 7-Segment-Anzeigen im Mittelpunkt stehen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Material<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Raspberry Pi mit Netzteil<\/li>\n\n\n\n<li>Breadboard und Jumper-Kabel<\/li>\n\n\n\n<li>Analog-Digital-Wandler MCP3002<\/li>\n\n\n\n<li>Kleinteile aus dem Set <span data-tooltip=\"158980\" class=\"dhsv-product-tooltip\">PAD-PRO-EXSB<\/span><\/li>\n<\/ul>\n\n\n<div class=\"alignnone wp-block-dhsv-product-teaser\">\n    <div data-component=\"ProductTeaser\" data-props=\"{&quot;productIds&quot;:&quot;158980&quot;,&quot;view&quot;:&quot;list&quot;,&quot;align&quot;:&quot;none&quot;,&quot;slider&quot;:false,&quot;sliderMobile&quot;:false}\"><\/div>\n<\/div>\n\n\n\n<div style=\"height:15px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"has-gray-lightest-100-background-color has-background\" style=\"padding-top:var(--wp--preset--spacing--20);padding-right:var(--wp--preset--spacing--20);padding-bottom:var(--wp--preset--spacing--20);padding-left:var(--wp--preset--spacing--20)\"><strong>\u00dcber den Autor<br><\/strong>Dr. G\u00fcnter Spanner ist als Autor zu den Themen Elektronik, Sensortechnik und Mikrocontroller einem weiten Fachpublikum bekannt. Schwerpunkt seiner hauptberuflichen T\u00e4tigkeit f\u00fcr verschiedene Gro\u00dfkonzerne wie Siemens und ABB ist die Projektleitung im Bereich Entwicklung und Technologie-Management. Der Dozent fu\u0308r Physik und Elektrotechnik hat zudem zahlreiche Fachartikel und Bu\u0308cher vero\u0308ffentlicht sowie Kurse und Lernpakete erstellt.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Virtuelle Instrumente ersetzen teure Messger\u00e4te und bringen Datenanalyse direkt auf den Raspberry Pi. Dieser Beitrag zeigt, wie mit Python und dem ADC MCP3002 Oszilloskope, Bargraphanzeigen oder Wetterstationen realisiert werden \u2013 praxisnah und kosteng\u00fcnstig.<\/p>\n","protected":false},"author":5,"featured_media":864,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[34],"tags":[122,126,123,125,124],"post-author":[137],"class_list":["post-839","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-python-micropython","tag-bargraphanzeige-tkinter","tag-openweathermap-klimastation","tag-raspberry-pi-mcp3002","tag-virtuelle-instrumente-python-aufbauen","tag-virtuelles-oszilloskop-python","post-author-dr-guenter-spanner"],"acf":[],"info":{"thumbnail":{"url":"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/header_phyton_teil11.jpg","alt":""},"teaserImage":{"ID":2143,"id":2143,"title":"liste-beitrag_python_t11","filename":"Liste-Beitrag_python_t11.jpg","filesize":57730,"url":"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Liste-Beitrag_python_t11.jpg","link":"https:\/\/de.elv.com\/elvjournal\/virtuelle-instrumente-python-raspberrypi\/liste-beitrag_python_t11\/","alt":"","author":"5","description":"","caption":"","name":"liste-beitrag_python_t11","status":"inherit","uploaded_to":839,"date":"2025-09-03 15:10:04","modified":"2025-09-03 15:10:04","menu_order":0,"mime_type":"image\/jpeg","type":"image","subtype":"jpeg","icon":"https:\/\/elvjournal.elv.com\/wp-includes\/images\/media\/default.png","width":312,"height":198,"sizes":{"thumbnail":"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Liste-Beitrag_python_t11-250x198.jpg","thumbnail-width":250,"thumbnail-height":198,"medium":"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Liste-Beitrag_python_t11-300x190.jpg","medium-width":300,"medium-height":190,"medium_large":"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Liste-Beitrag_python_t11.jpg","medium_large-width":312,"medium_large-height":198,"large":"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Liste-Beitrag_python_t11.jpg","large-width":312,"large-height":198,"1536x1536":"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Liste-Beitrag_python_t11.jpg","1536x1536-width":312,"1536x1536-height":198,"2048x2048":"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Liste-Beitrag_python_t11.jpg","2048x2048-width":312,"2048x2048-height":198,"gform-image-choice-sm":"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Liste-Beitrag_python_t11.jpg","gform-image-choice-sm-width":300,"gform-image-choice-sm-height":190,"gform-image-choice-md":"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Liste-Beitrag_python_t11.jpg","gform-image-choice-md-width":312,"gform-image-choice-md-height":198,"gform-image-choice-lg":"https:\/\/elvjournal.elv.com\/wp-content\/uploads\/Liste-Beitrag_python_t11.jpg","gform-image-choice-lg-width":312,"gform-image-choice-lg-height":198}},"categories":[{"id":34,"name":"Python &amp; MicroPython","slug":"python-micropython"}],"authors":[{"id":137,"name":"Dr. G\u00fcnter Spanner","slug":"dr-guenter-spanner"}],"document":false,"epaper":"","date":"24. September 2025","excerpt":"Virtuelle Instrumente ersetzen teure Messger\u00e4te und bringen Datenanalyse direkt auf den Raspberry Pi. Dieser Beitrag zeigt, wie mit Python und dem ADC MCP3002 Oszilloskope, Bargraphanzeigen oder Wetterstationen realisiert werden \u2013 praxisnah und kosteng\u00fcnstig."},"_links":{"self":[{"href":"https:\/\/de.elv.com\/elvjournal\/wp-json\/wp\/v2\/posts\/839","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/de.elv.com\/elvjournal\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/de.elv.com\/elvjournal\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/de.elv.com\/elvjournal\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/de.elv.com\/elvjournal\/wp-json\/wp\/v2\/comments?post=839"}],"version-history":[{"count":10,"href":"https:\/\/de.elv.com\/elvjournal\/wp-json\/wp\/v2\/posts\/839\/revisions"}],"predecessor-version":[{"id":11590,"href":"https:\/\/de.elv.com\/elvjournal\/wp-json\/wp\/v2\/posts\/839\/revisions\/11590"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/de.elv.com\/elvjournal\/wp-json\/wp\/v2\/media\/864"}],"wp:attachment":[{"href":"https:\/\/de.elv.com\/elvjournal\/wp-json\/wp\/v2\/media?parent=839"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/de.elv.com\/elvjournal\/wp-json\/wp\/v2\/categories?post=839"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/de.elv.com\/elvjournal\/wp-json\/wp\/v2\/tags?post=839"},{"taxonomy":"post-author","embeddable":true,"href":"https:\/\/de.elv.com\/elvjournal\/wp-json\/wp\/v2\/post-author?post=839"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}