7. ウェブサーバーのセットアップ

この記事では、Pico Wをブラウザから回路を操作したり、センサーからの読み取りを取得できるウェブサーバーにする方法を学びます。

setup_web

1. 必要なコンポーネント

このプロジェクトには、以下のコンポーネントが必要です。

一式を購入すると便利です。こちらがリンクです:

名前

このキットに含まれるアイテム

リンク

ケプラーキット

450+

Kepler Kit

以下のリンクから個別に購入することもできます。

SN

コンポーネント

数量

リンク

1

Raspberry Pi Pico W

1

BUY

2

マイクロUSBケーブル

1

3

ブレッドボード

1

BUY

4

ジャンパーワイヤー

数本

BUY

5

抵抗器

4(1-330Ω, 2-220Ω, 1-10KΩ)

BUY

6

RGB LED

1

BUY

7

サーミスター

1

BUY

8

Li-po充電モジュール

1

9

18650バッテリー

1

10

バッテリーホルダー

1

2. 回路を組み立てる

警告

図に示されている通り、Li-poチャージャーモジュールが接続されていることを確認してください。そうでないと、ショート回路が起きてバッテリーや回路が損傷する可能性があります。

../_images/7.web_page_bb.png

3. コードを実行する

  1. kepler-kit-main/iot のパスの下にある 7_web_page.py ファイルを開きます。

  2. Run current script ボタンをクリックするか、F5キーを押して実行します。接続が成功すると、Pico WのIPが表示されます。

    ../_images/7_web_server.png

    注釈

    コードを実行する前に、Pico Wに do_connect.pysecrets.py スクリプトがあることを確認してください。もしなければ、 1. ネットワークへのアクセス を参照して作成してください。

  3. Pico WのIPアドレスをブラウザに入力して、このプロジェクトのために構築されたウェブページにアクセスします。任意のボタンをクリックして、RGB LEDの色を変更し、温度と湿度を更新します。

    ../_images/web-1.png
  4. このスクリプトを起動できるようにしたい場合は、Raspberry Pi Pico Wに main.py として保存できます。

動作原理は?

アクセスしているウェブページは実際には何らかのサーバーでホストされており、そのサーバーのソケットが訪問時にウェブページを送信します。 ソケットとは、サーバーが接続を希望するクライアントを待ち受ける方法です。

このプロジェクトでは、Pico Wがサーバーであり、ブラウザを介してPico Wでホストされているウェブページにアクセスしています。

最初にソケットを作成します。これにはIPアドレスと port が必要です。 ネットワーク接続とIPの取得方法は、 1. ネットワークへのアクセス で説明されています。ポートには80を使用します。 ソケットの設定が完了したら、それを返して次のステップで使用します。

socket library - Python Docs

import socket

def open_socket(ip):
    # ソケットを開く
    address = (ip, 80)
    connection = socket.socket()
    connection.bind(address)
    connection.listen(1)
    print(connection)
    return(connection)

次に、以前に設定したソケットを使用してウェブサービスを設定します。 以下のコードにより、Pico Wはブラウザからのアクセス要求を受け取ることができます。

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

次に、訪問者に送信するhtmlページが必要です。この例では、変数 html に文字形式で単純なhtmlページを格納しています。

注釈

自分でhtmlを書きたい場合は、 HTML.COM でヘルプを得ることができます。

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>温度は{value}度です</p>
            </body>
            </html>
            """
    return html

訪問者にHTMLページを送信する。

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

上記の部分を組み合わせると、ブラウザでページにアクセスできます。効果を確認したい場合は、以下のコードをThonnyで実行してください。

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="赤" />
            </form>
            <form action="./green">
            <input type="submit" value="緑" />
            </form>
            <form action="./blue">
            <input type="submit" value="青" />
            </form>
            <form action="./off">
            <input type="submit" value="オフ" />
            </form>
            <p>温度は{value}度です</p>
            </body>
            </html>
            """
    return html

def open_socket(ip):
    # ソケットを開く
    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()

上記のコードを実行すると、ウェブページのみが表示され、RGB LEDの制御やセンサーの読み取りは許可されていないことがわかります。 このウェブサービスはさらに洗練される必要があります。

最初に知るべきことは、ブラウザがウェブページにアクセスしたときにサーバーが受け取る情報です。それゆえに、 serve() をわずかに変更して request を出力します。

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()

スクリプトを再実行すると、シェルはウェブページでキーを押すときに以下のメッセージを出力します。

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'

読むには長すぎます!

しかし、実際に必要なのは /red?/blue? の前にある小さな情報だけです。 これはどのボタンが押されたのかを教えてくれます。それで、キーストロークの情報を抽出するために serve() を少し改良しました。

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()

プログラムを再実行すると、ウェブページでキーを押すと、シェルは以下のようなメッセージを出力します。

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

次に、 request の値に応じてRGB LEDの色を変更するだけです。

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()

最後に、ウェブページにサーミスターの値を表示する必要があります(サーミスターの使用方法の詳細については、 2.13 温度計 を参照してください)。 この部分は実際にはHTMLのテキストを修正することで実現されます。 webpage(value) 関数でパラメータを設定し、入力パラメータを変更するだけでウェブページに表示される数字を変更します。

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()