Raspberry Pi Pico Wでビジネス用キャプティブ・ポータルを作る方法

raspberry pi pico w キャプティブポータルのセットアップ

もしあなたがビジネスを運営しているなら、キャプティブ・ポータルを設定することはネットワークにとって重要なツールになります。そこで今回は、Raspberry Pi Pico Wを使ってキャプティブ・ポータルを作成する方法を紹介します。

キャプティブポータルは、ゲスト、顧客、またはクライアントにWiFiを提供する安全な方法を提供します。ユーザーがインターネットを利用する前に、ログインまたは認証を行う必要があります。

空港やコーヒーショップのチェーン店での仕組みを考えてみよう。

キャプティブ・ポータルは、ネットワークの制御と監視の両方を可能にします。また、ブランドを拡大する機会にもなります。キャプティブポータルをロゴでカスタマイズできます。

キャプティブ・ポータルは何をするのか?

アクセスポイントとして動作しているPico Wにログオンしても、ウェブページは表示されません。キャプティブポータルが実装されていれば、WiFiがホットスポットに接続すると、ウェブページがポップアップ表示されます。

そのため、ネットワークに接続し、ブラウザでIPアドレスを手入力するステップを省くことができる。

この時点で、私は次のように評価しなければならない。 このチュートリアルのベースとなるビデオを提供してくれたケビン・マカリア。

Pico Wでキャプティブポータルを作るのは素晴らしい機会です。キャプティブ・ポータルはビジネス・ネットワークに不可欠なだけではありません。A Raspberry Pi Pico W 最大でも数ユーロなので、非常に費用対効果の高いソリューションでもある。

このチュートリアルの目標

Kevinのチュートリアルでは、Appleデバイス上でキャプティブポータルを起動する方法のみを紹介しています。

このチュートリアルでは、さらに踏み込んで、Android、Windows、Appleデバイスでポップアップ・キャプティブ・ポータルを起動する方法を説明します。

PhewはPico Wウェブサーバー用のライブラリだ。NodeJSにとってのExpressのようなものだ。

私のコードを4つのデバイスでテストした:

  • Apple iPhone 8、OSバージョンは15.4.1 ✔️
  • Android 9搭載Amazon Fireタブレット ✔️
  • Windows 10 PC ✔️
  • Google Pixel 6 with Android 13 ✔️
  • アンドロイド10を搭載したサムスン・ノート9

このコードは、私のサムスン・ノート9を除くすべての機種で動作し、Linuxではテストしていない。

使用例?

これはちょっと難しい。

当初は、誰かをリックロールするようなものを作りたかったのだが、ピコWにはインターネット接続がないため、YouTubeの動画を埋め込むことができないことに気づいた。

そこで私は、人々がPico Wに接続し、いくつかのリンクを見ることができる携帯用デジタル名刺を作りたかった。インスタグラムのリンク・イン・バイオ・ディレクトリーのようなものだ。ここでもインターネットは使えない。

ピコWの最大の利点は、ワイヤレスでコンポーネントをコントロールできることだろう。

コンポーネント・メガ・チュートリアル前回は、LED、ブザー、サーボを制御するために物理的なボタンやノブを使わずに、代わりにウェブインターフェースを使用する方法について説明しました。これらをキャプティブポータルに実装すれば、コントロールパネルにアクセスするたびに192.168.4.1にログインする必要がなくなるので、より簡単にデバイスをコントロールできるようになります。

もちろん、あなたが考えるキャプティブ・ポータルの可能性をぜひお聞かせください。以下にコメントを残してください!

ポップアップの出し方

ワイヤレス・ネットワークに接続すると、ウィンドウズ、アンドロイド、アップルの各デバイスは、それぞれ異なるウェブサイトにpingを送信する。

これらのPingにはそれぞれ返信が必要です。正しい返信をすることで、ポップアップのロックが解除される。以下は、OSによって異なる会話の流れである:

マイクロソフト・ウィンドウズ10

MS:「Psst...は/です。connecttest.txt そこに?"

ピコW「そうだね、 200“.

MS:「よし、連れて行ってくれ /リダイレクト

ピコW:「うーん、そうだね、 302にアクセスする。 http://pico.wireless/ サービス提供場所 索引.html“.

アマゾン・ファイア Android 9

AMZ:"Psst...どこだ? /generate_204 そこに?"

ピコW:「デフォルトでは、こう言うつもりだった。 204でも、あなたが本当に望んでいるのは 302 にリダイレクトする。 http://pico.wireless/ (index.html、別名キャプティブページをレンダリングする)"

アップル iPhone 8 iOS 15搭載

iPhone:"僕はクールだから、ファイルを探しているんだ /hotspot-detect.html

ピコW:「そうだ。 http://pico.wireless/

iPhone:"うーん、僕が頼んだのとは全然違うようだけど、君を信頼しているから、これから行ってみるよ"

レスポンスコード 200: "OK", 204:「コンテンツがありません」、302:「見つかりました」。

ご覧のように、異なるデバイスは異なるルートと異なるウェブページを要求する。そして、正しく返答すれば、ポップアップが表示される。

送受信に必要なものをまとめてみました:

Windows 10

URL反応を引き起こす
www.msftconnecttest.com/ncsi.txt200 OK
www.msftconnecttest.com/connecttest.txt200 OK
www.msftconnecttest.com/redirect302リダイレクト(キャプティブ・ポータルへ、例:index.html)

アンドロイド 9, 10

URL反応を引き起こす
connectivitycheck.gstatic.com/generate_204302リダイレクト(キャプティブポータルページへ)

他のアンドロイド・バージョンは、他のURLを照会するかもしれない。新しいAndroidのバージョンでは /generate_204 フォールバックとして。

古いアンドロイド用のリソースを2つ紹介しよう:

https://lemariva.com/blog/2017/11/white-hacking-wemos-captive-portal-using-micropython

https://enterprisenetworkingatlarge.wordpress.com/2018/04/21/captive-portal-detection-on-android-and-others-client-vendors-vs-ap-vendors/

iOS 15

URL反応を引き起こす
captive.apple.com/hotspot-detect.html200 OK (ウェブページで応答)

アンドロイド10を実行している私のサムスンノート9は、クラックするのが最も難しかった。表向きは典型的なアンドロイドのパターンに従えばいいのだが、残念ながら何もうまくいかなかった!

サインインが必要です」というプロンプトは何とか表示されたが、DNSをパブリックLANのIP(「10.0.0.0/8、172.16.0.0/12、または192.168.0.0/16」の範囲外のIP)に変更した後だった。 このStack Exchangeのコメントを見てほしい。

しかし、上記のことをすると、他のすべてのデバイスのキャプティブポータルが壊れてしまう...。

ピコWキャプティブ・ポータル用Pimoroni Phewライブラリ

ピモロニのふぅ ライブラリーがあれば、キャプティブ・ポータルの作成が非常に簡単になる。

まず、ライブラリをダウンロードする必要がある。私は0.0.3バージョンを使用した ダウンロードはこちらから。

その後、ファイルを解凍し、以下のフォルダをアップロードします。 ふぅ 個人的には、Thonny IDEを使いました。 ファイルのアップロード方法はこちらをご覧ください。

チュートリアルが終わるころには、次のようなディレクトリができているはずだ。

ホットスポットのポップアップをコーディングしよう!

では、まずはじめに main.py:

from phew import logging, server, access_point, dns
from phew.template import render_template
from phew.server import redirect

DOMAIN = "pico.wireless"  # This is the address that is shown on the Captive Portal


@server.route("/", methods=['GET'])
def index(request):
    """ Render the Index page"""
    if request.method == 'GET':
        logging.debug("Get request")
        return render_template("index.html")

# microsoft windows redirects
@server.route("/ncsi.txt", methods=["GET"])
def hotspot(request):
    print(request)
    print("ncsi.txt")
    return "", 200


@server.route("/connecttest.txt", methods=["GET"])
def hotspot(request):
    print(request)
    print("connecttest.txt")
    return "", 200


@server.route("/redirect", methods=["GET"])
def hotspot(request):
    print(request)
    print("****************ms redir*********************")
    return redirect(f"http://{DOMAIN}/", 302)

# android redirects
@server.route("/generate_204", methods=["GET"])
def hotspot(request):
    print(request)
    print("******generate_204********")
    return redirect(f"http://{DOMAIN}/", 302)

# apple redir
@server.route("/hotspot-detect.html", methods=["GET"])
def hotspot(request):
    print(request)
    """ Redirect to the Index Page """
    return render_template("index.html")


@server.catchall()
def catch_all(request):
    print("***************CATCHALL***********************\n" + str(request))
    return redirect("http://" + DOMAIN + "/")


# Set to Accesspoint mode
# Change this to whatever Wifi SSID you wish
ap = access_point("Pico W Captive")
ip = ap.ifconfig()[0]
# Grab the IP address and store it
logging.info(f"starting DNS server on {ip}")
# # Catch all requests and reroute them
dns.run_catchall(ip)
server.run()                            # Run the server
logging.info("Webserver Started")

誤解のないように言っておくが、私はこのコードをケヴィン・マカレアから引用し、我々の目的に合わせて変更した。ケヴィンの詳細な説明をご覧になりたい方は、こちらをクリックしてください、 YouTubeのビデオをご覧ください。

しかし、各セクションについて簡単に説明しよう。

#android redirects"、"#apple redir"、"# microsoft windows redirects "の3つのセクションがある。これらのセクションは、各オペレーティングシステムが出すテストを処理し、適切なレスポンスを返します。

レスポンスの最後には、アップルルートを除いて、http://{DOMAIN}/にリダイレクトされます(ケビンがそのように書いたので、もし壊れていなければ...)。

"pico.wireless "として宣言されたDOMAINにリダイレクトすれば、見苦しくないURLが得られるだろう。

つまり、アドレスバーに "www.msftconnecttest.com "と表示される代わりに、"pico.wireless "と表示されることになる。もちろん、これはあなたのビジネスのキャプティブ・ポータルで覚えておくべきことだ。

ピモロニ ふぅ、書くべきコードが減った

Phewの素晴らしいところは、ゼロからコードを書くよりも大幅に少ないコードで済むことだ。

例えば、ピコWでソフトAPを起動させたい場合、次のようなコードを書くことになる:

import network
# start up network in access point mode
wlan = network.WLAN(network.AP_IF)
wlan.config(essid=ssid)
if password:
    wlan.config(password=password)
else:
    wlan.config(security=0)  # disable password
wlan.active(True)
return wlan

ピモロニの「ふぅ」があれば、あなたの負担は軽減される:

ap = access_point("Pico W Captive")

私の意見では、最高の部分は dns.run_catchall() この関数は、重要だが複雑なコードを実行する:

import uasyncio, usocket
from . import logging

async def _handler(socket, ip_address):
  while True:
    try:
      yield uasyncio.core._io_queue.queue_read(socket)
      request, client = socket.recvfrom(256)
      response = request[:2] # request id
      response += b"\x81\x80" # response flags
      response += request[4:6] + request[4:6] # qd/an count
      response += b"\x00\x00\x00\x00" # ns/ar count
      response += request[12:] # origional request body
      response += b"\xC0\x0C" # pointer to domain name at byte 12
      response += b"\x00\x01\x00\x01" # type and class (A record / IN class)
      response += b"\x00\x00\x00\x3C" # time to live 60 seconds
      response += b"\x00\x04" # response length (4 bytes = 1 ipv4 address)
      response += bytes(map(int, ip_address.split("."))) # ip address parts
      socket.sendto(response, client)
    except Exception as e:
      logging.error(e)

def run_catchall(ip_address, port=53):
  logging.info("> starting catch all dns server on port {}".format(port))

  _socket = usocket.socket(usocket.AF_INET, usocket.SOCK_DGRAM)
  _socket.setblocking(False)
  _socket.setsockopt(usocket.SOL_SOCKET, usocket.SO_REUSEADDR, 1)
  _socket.bind(usocket.getaddrinfo(ip_address, port, 0, usocket.SOCK_DGRAM)[0][-1])

  loop = uasyncio.get_event_loop()
  loop.create_task(_handler(_socket, ip_address))

Phewはルートを書くのも簡単だ。こんな風に書くだけでいい:

@server.route("/[your_route_here]", methods=["GET"])
def your_function_here(request):
  pass

@server.catchall()
def catchall(request):
  pass

上にあるように、ルートの作成はとても簡単です。必要なのは サーバー・ルートメソッドと同様にルートを渡す。次に リクエスト パラメータが必要だ。

最後に サーバー.catchall() 関数は、あなたが割り当てていないすべてのルートを処理します。

ふぅ、超簡単になった!

PhewのGithubリポジトリはこちら。

索引.html

実にシンプルな概念実証だ。 索引.html を出す。 <h1> Pico W Captive Portal」と言う。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Pico W Captive Portal</title>
  </head>
  <body>
    <h1>Pico W Captive Portal</h1>
  </body>
</html>

結論

これで完了です。Pico Wにキャプティブ・ポータルを設置するために必要な知識は以上です。

ご質問があれば、遠慮なく下のコメントでお知らせください!

8コメント

  1. cinos on 1月 8, 2023 at 4:11 pm となります。

    海賊版ボックスの良い代替品だ(チャット機能とアップロードはないが)。

  2. OkinKun on 3月 31, 2023 at 5:07 pm となります。

    これこそ私が探していたものだ!
    しかし、ウェブサイトが勝手に立ち上がらず、エラーが表示される:

    2023-03-31 12:02:35 [info / 160kB] > GET /generate_204 (302 Found) [236ms]
    タスク例外が取得されなかった
    future:コロ
    Traceback (most recent call last):
    ファイル "uasyncio/core.py", 行 1, in run_until_complete
    ファイル "phew/server.py", 行 242, in _handle_request
    ファイル "phew/server.py", 行 161, in _parse_headers
    ValueError: アンパックするには1つ以上の値が必要です。

    もしかしたら、僕の古い携帯電話がまだアンドロイド6であることと関係があるのかもしれない...。

  3. Dingleberry on 6月 21, 2023 at 10:57 pm となります。

    プログラム内にHTMLコードを含めるために、そのコードをどのように編集するのでしょうか?私は試してみましたが、うまくいきませんでした。

    プログラムの流れが非常にわかりにくい。

    • Adam Bobeck on 6月 26, 2023 at 2:51 pm となります。

      こんにちは!問題の詳細と、キャプティブポータルに使用しているデバイスを教えてください。

  4. NewbiePicoWHacker on 10月 1, 2023 at 3:36 pm となります。

    こんにちは! APが起動し、DNSが起動し、ウェブサーバーは起動しないか、起動に長い時間(数分)かかります。 APは起動し、DNSは起動するのですが、ウェブサーバーは起動しないか、起動に長い時間(数分)かかります。 ありがとうございます!

  5. Prithwiraj Bose on 11月 5, 2023 at 3:43 pm となります。

    ホットスポットへの接続に成功した後、どのコードの行がクライアントのブラウザ上でキャプティブポータルを強制/自動オープンするのかを理解する手助けをしてもらえますか?自動では何も開かないようです。私はラップトップから接続しています。

  6. Peter on 11月 24, 2023 at 8:13 pm となります。

    いい説明をありがとう。

    同じAPに2つ目、あるいは3つ目のSSIDを追加したい。Phewでそれをする方法はありますか?

    何かお考えは?

    • Toby on 5月 28, 2024 at 5:13 pm となります。

      いや、それぞれのssidにラズベリーパイpicoを使う必要がある。

コメントを残す