.. note::

    Hallo und willkommen in der SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasten-Gemeinschaft auf Facebook! Tauchen Sie tiefer ein in die Welt von Raspberry Pi, Arduino und ESP32 mit anderen Enthusiasten.

    **Warum beitreten?**

    - **Expertenunterstützung**: Lösen Sie Nachverkaufsprobleme und technische Herausforderungen mit Hilfe unserer Gemeinschaft und unseres Teams.
    - **Lernen & Teilen**: Tauschen Sie Tipps und Anleitungen aus, um Ihre Fähigkeiten zu verbessern.
    - **Exklusive Vorschauen**: Erhalten Sie frühzeitigen Zugang zu neuen Produktankündigungen und exklusiven Einblicken.
    - **Spezialrabatte**: Genießen Sie exklusive Rabatte auf unsere neuesten Produkte.
    - **Festliche Aktionen und Gewinnspiele**: Nehmen Sie an Gewinnspielen und Feiertagsaktionen teil.

    👉 Sind Sie bereit, mit uns zu erkunden und zu erschaffen? Klicken Sie auf [|link_sf_facebook|] und treten Sie heute bei!

7. Ein Webserver einrichten
====================================

In diesem Artikel erfahren Sie, wie Sie den Pico W in einen Webserver verwandeln, über den Sie Schaltkreise steuern und Sensordaten direkt aus Ihrem Browser abrufen können.

|setup_web|

**1. Benötigte Komponenten**

Für dieses Projekt benötigen Sie die folgenden Bauteile.

Ein komplettes Bausatz ist natürlich praktisch. Hier ist der Link dazu:

.. list-table::
    :widths: 20 20 20
    :header-rows: 1

    *   - Bezeichnung
        - BESTANDTEILE IN DIESEM KIT
        - LINK
    *   - Kepler Kit
        - Über 450
        - |link_kepler_kit|

Die einzelnen Komponenten können Sie auch über die folgenden Links erwerben.

.. list-table::
    :widths: 5 20 5 20
    :header-rows: 1

    *   - SN
        - KOMPONENTE	
        - ANZAHL
        - LINK

    *   - 1
        - :ref:`cpn_pico_w`
        - 1
        - |link_picow_buy|
    *   - 2
        - Micro-USB-Kabel
        - 1
        - 
    *   - 3
        - :ref:`cpn_breadboard`
        - 1
        - |link_breadboard_buy|
    *   - 4
        - :ref:`cpn_wire`
        - Mehrere
        - |link_wires_buy|
    *   - 5
        - :ref:`cpn_resistor`
        - 4(1-330Ω, 2-220Ω, 1-10KΩ)
        - |link_resistor_buy|
    *   - 6
        - :ref:`cpn_rgb`
        - 1
        - |link_rgb_led_buy|
    *   - 7
        - :ref:`cpn_thermistor`
        - 1
        - |link_thermistor_buy|
    *   - 8
        - :ref:`cpn_lipo_charger`
        - 1
        -  
    *   - 9
        - 18650-Batterie
        - 1
        -  
    *   - 10
        - Batteriehalter
        - 1
        -  

**2. Schaltung aufbauen**

    .. warning::

        Achten Sie darauf, dass Ihr Li-Po-Ladegerät genau wie im Schaltplan angeschlossen ist. Andernfalls könnte ein Kurzschluss Ihre Batterie und die Schaltung beschädigen.

.. image:: img/wiring/7.web_page_bb.png
    :width: 800


**3. Code ausführen**

#. Öffnen Sie die Datei ``7_web_page.py`` im Ordner ``kepler-kit-main/iot``.
#. Klicken Sie auf die Schaltfläche **Aktuelles Skript ausführen** oder drücken Sie F5. Nach erfolgreicher Verbindung wird die IP-Adresse des Pico W angezeigt.

    .. image:: img/7_web_server.png

    .. note::

        Bevor Sie den Code ausführen, stellen Sie sicher, dass die Skripte ``do_connect.py`` und ``secrets.py`` auf Ihrem Pico W vorhanden sind. Wenn nicht, folgen Sie den Anweisungen unter :ref:`iot_access`, um sie zu erstellen.

#. Geben Sie die IP-Adresse des Pico W in Ihren Browser ein, um die für dieses Projekt erstellte Webseite aufzurufen. Klicken Sie auf einen beliebigen Button, um die Farbe der RGB-LEDs zu ändern und die Temperatur sowie die Luftfeuchtigkeit zu aktualisieren.

    .. image:: img/web-1.png
        :width: 500

#. Wenn Sie möchten, dass dieses Skript beim Start ausgeführt wird, speichern Sie es als ``main.py`` auf dem Raspberry Pi Pico W.


**Wie funktioniert es?**

Die Webseite, die Sie besuchen, wird tatsächlich auf einem Server gehostet. Der Socket auf dem Server sendet uns die Webseite, sobald wir sie aufrufen.
Ein Socket ist die Methode, mit der ein Server auf einen Client hören kann, der eine Verbindung herstellen möchte.

In diesem Projekt fungiert Pico W als Ihr Server, und Ihr Computer greift über einen Browser auf die auf Pico W gehostete Webseite zu.

Zuerst erstellen wir einen Socket, der eine IP-Adresse und einen |link_port| benötigt.
Details zur Netzwerkverbindung und zur Ermittlung der IP-Adresse finden Sie unter :ref:`iot_access`. Als Port verwenden wir 80.
Nachdem der Socket eingerichtet ist, geben wir ihn zurück und verwenden ihn für den nächsten Schritt.

`Socket-Bibliothek - Python Docs <https://docs.python.org/3/library/socket.html>`_

.. code-block:: python

    import socket

    def open_socket(ip):
        # Einen Socket öffnen
        address = (ip, 80)
        connection = socket.socket()
        connection.bind(address)
        connection.listen(1)
        print(connection)
        return connection

Anschließend richten Sie Ihren Webdienst ein, bei dem der zuvor eingerichtete Socket zum Einsatz kommt.
Der folgende Code ermöglicht es Ihrem Pico W, Zugriffsanfragen von Ihrem Browser entgegenzunehmen.

.. code-block:: python

    def serve(connection):
        while True:
            client = connection.accept()[0]
            request = client.recv(1024)
            client.close()

Als Nächstes benötigen Sie eine HTML-Seite, die Sie dem Besucher senden können. Dieses Beispiel speichert eine einfache HTML-Seite in Form von Zeichen in der Variablen ``html``.

.. note:: 
    Wenn Sie in der Lage sein möchten, Ihr eigenes HTML zu schreiben, können Sie Hilfe unter |link_html| finden.

.. code-block:: python

    def webpage(value):
        html = f"""
                <!DOCTYPE html>
                <html>
                <body>
                <form action="./red">
                <input type="submit" value="Rot" />
                </form>
                <form action="./green">
                <input type="submit" value="Grün" />
                </form>
                <form action="./blue">
                <input type="submit" value="Blau" />
                </form>
                <form action="./off">
                <input type="submit" value="Aus" />
                </form>
                <p>Die Temperatur beträgt {value} Grad Celsius</p>
                </body>
                </html>
                """
        return html

HTML-Seite an den Besucher senden.

.. code-block:: python
    :emphasize-lines: 5,6

    def serve(connection):
        while True:
            client = connection.accept()[0]
            request = client.recv(1024)
            html=webpage(0)
            client.send(html)
            client.close()


Die Seite kann über Ihren Browser aufgerufen werden, wenn Sie die oben genannten Teile kombinieren. Um die Wirkung zu sehen, führen Sie den unten stehenden Code mit Thonny aus.

.. code-block:: python

    import machine
    import socket

    from secrets import *
    from do_connect import *

    def webpage(value):
        html = f"""
                <!DOCTYPE html>
                <html>
                <body>
                <form action="./red">
                <input type="submit" value="red " />
                </form>
                <form action="./green">
                <input type="submit" value="green" />
                </form>
                <form action="./blue">
                <input type="submit" value="blue" />
                </form>
                <form action="./off">
                <input type="submit" value="off" />
                </form>
                <p>Temperature is {value} degrees Celsius</p>
                </body>
                </html>
                """
        return html

    def open_socket(ip):
        # Open a socket
        address = (ip, 80)
        connection = socket.socket()
        connection.bind(address)
        connection.listen(1)
        print(connection)
        return(connection)

    def serve(connection):
        while True:
            client = connection.accept()[0]
            request = client.recv(1024)
            html=webpage(0)
            client.send(html)
            client.close()

    try:
        ip=do_connect()
        if ip is not None:
            connection=open_socket(ip)
            serve(connection)
    except KeyboardInterrupt:
        machine.reset()

Wenn Sie den obigen Code ausführen, werden Sie feststellen, dass lediglich eine Webseite angezeigt wird; eine Steuerung der RGB-LEDs oder die Anzeige von Sensorwerten ist nicht möglich. Der Webdienst muss weiter verfeinert werden.

Zunächst müssen wir wissen, welche Informationen der Server erhält, wenn der Browser auf die Webseite zugreift. Ändern Sie deshalb die Funktion ``serve()`` geringfügig, um ``request`` auszugeben.

.. code-block:: python
    :emphasize-lines: 5,6

    def serve(connection):
        while True:
            client = connection.accept()[0]
            request = client.recv(1024)
            request = str(request)
            print(request)  
            html=webpage(0)
            client.send(html)
            client.close()

Führen Sie das Skript erneut aus, und die Shell wird die folgende Nachricht ausgeben, wenn wir eine Taste auf der Webseite drücken.

.. code-block:: 

    b'GET /red? HTTP/1.1\r\nHost: 192.168.18.162\r\nConnection: keep-alive.......q=0.5\r\n\r\n'
    b'GET /favicon.ico HTTP/1.1\r\nHost: 192.168.18.162\r\nConnection: keep-alive.......q=0.5\r\n\r\n'
    b'GET /blue? HTTP/1.1\r\nHost: 192.168.18.162\r\nConnection: keep-alive.......q=0.5\r\n\r\n'
    b'GET /favicon.ico HTTP/1.1\r\nHost: 192.168.18.162\r\nConnection: keep-alive.......q=0.5\r\n\r\n'

Das ist zu viel zum Lesen!

Was wir wirklich benötigen, ist jedoch nur der kleine Informationsbrocken vor ``/red?``, ``/blue?``.
Er zeigt uns an, welcher Knopf gedrückt wurde. Deshalb haben wir ``serve()`` leicht modifiziert, um die Tasteninformation zu extrahieren.

.. code-block:: python
    :emphasize-lines: 6,7,8,9

    def serve(connection):
        while True:
            client = connection.accept()[0]
            request = client.recv(1024)
            request = str(request)
            try:
                request = request.split()[1]
            except IndexError:
                pass
            print(request)  
            html=webpage(0)
            client.send(html)
            client.close()

Führen Sie das Programm erneut aus, und die Shell wird die folgende Nachricht ausgeben, wenn wir eine Taste auf der Webseite drücken.

.. code-block::

    /red?
    /favicon.ico
    /blue?
    /favicon.ico
    /off?
    /favicon.ico

Anschließend müssen wir nur noch die Farbe der RGB-LED entsprechend dem Wert von ``request`` ändern.

.. code-block:: python

    def serve(connection):
        while True:
            client = connection.accept()[0]
            request = client.recv(1024)
            request = str(request)
            try:
                request = request.split()[1]
            except IndexError:
                pass
            
            print(request)
            
            if request == '/off?':
                red.low()
                green.low()
                blue.low()
            elif request == '/red?':
                red.high()
                green.low()
                blue.low()
            elif request == '/green?':
                red.low()
                green.high()
                blue.low()
            elif request == '/blue?':
                red.low()
                green.low()
                blue.high()
 
            html=webpage(0)
            client.send(html)
            client.close()

Zuletzt soll der Thermistorwert auf der Webseite angezeigt werden (siehe :ref:`py_temp` für Details zur Verwendung des Thermistors).
Dies wird tatsächlich durch Ändern des Texts im HTML erreicht. 
Wir setzen die Parameter in der Funktion ``webpage(value)`` und ändern einfach die eingehenden Parameter, um die auf der Webseite angezeigte Zahl zu ändern.

.. code-block:: python
    :emphasize-lines: 30,31

        def serve(connection):
        while True:
            client = connection.accept()[0]
            request = client.recv(1024)
            request = str(request)
            try:
                request = request.split()[1]
            except IndexError:
                pass
            
            #print(request)
            
            if request == '/off?':
                red.low()
                green.low()
                blue.low()
            elif request == '/red?':
                red.high()
                green.low()
                blue.low()
            elif request == '/green?':
                red.low()
                green.high()
                blue.low()
            elif request == '/blue?':
                red.low()
                green.low()
                blue.high()

            value='%.2f'%temperature()    
            html=webpage(value)
            client.send(html)
            client.close()

.. https://projects.raspberrypi.org/en/projects/get-started-pico-w/3
