如何用 Raspberry Pi Pico W 制作企业专属门户网站
如果你正在经营一家企业,那么建立一个 "专属门户 "对你的网络来说可能是一个重要的工具。因此,在本文中,我将向你展示如何用 Raspberry Pi Pico W 创建一个专属门户。
专属门户提供了一种向客人、客户或顾客提供 WiFi 的安全方式。它要求用户在使用互联网之前先登录或进行身份验证。
想想机场或连锁咖啡店是如何运作的。
专属门户允许您控制和监控网络。它还提供了一个扩展品牌的机会。您可以用自己的徽标定制专属门户。
专用门户网站有什么作用?
当你登录作为接入点的 Pico W 时,不会有网页向你提供。如果使用了捕获式门户,一旦你的 WiFi 连接到热点,就会弹出一个网页。
因此,您可以跳过连接网络,然后在浏览器中手动输入 IP 地址的步骤。
在这一点上,我必须归功于 Kevin McAleer 的视频是本教程的基础。
使用 Pico W 创建专属门户网站是一个绝佳的机会。专属门户不仅是企业网络的当务之急。A 树莓派Pico W 最多只需几欧元,因此也是一个极具成本效益的解决方案。
本教程的目标
凯文的教程只向你展示了如何在苹果设备上触发一个专属门户。
本教程将进一步解释如何在安卓、Windows 和苹果设备上触发弹出式专属门户。
我们将使用 Pimoroni 的 Phew,这是一个 Pico W 网络服务器库。它有点像 Express 之于 NodeJS。
我已经在四台设备上测试了我的代码:
- 苹果 iPhone 8,操作系统版本 15.4.1 ✔️
- 配备 Android 9 的亚马逊 Fire 平板电脑 ✔️
- Windows 10 PC ✔️
- 搭载 Android 13 的谷歌 Pixel 6 ✔️
- 搭载 Android 10 ❌ 的三星 Note 9
除了我的三星 Note 9 外,代码在其他设备上都能正常运行,而且我还没有在 Linux 上测试过。
用例?
这个问题有点棘手。
起初,我想制作一些能让人嬉笑怒骂的东西,但我意识到我无法嵌入 YouTube 视频,因为 Pico W 没有互联网连接。
然后,我想制作一张便携式数字名片,让人们可以连接到 Pico W 并看到一些链接。有点像 Instagram 上的链接目录。同样,没有互联网...
我想,Pico W 最大的优势之一就是可以无线控制组件。
在 我们的组件大型教程我曾在一篇文章中谈到如何通过使用网络接口来避免使用物理按钮和旋钮来控制 LED、蜂鸣器和伺服器。如果将这些功能应用到您的专属门户中,您就可以更轻松地控制设备,因为您不必每次都登录 192.168.4.1 进入控制面板。
当然,我也很乐意听听您对圈定门户的看法。请在下面留言!
如何触发弹出窗口
当您连接到无线网络时,Windows、Android 和 Apple 设备会 ping 不同的网站。
每个 ping 都需要回复。正确的回复可以解锁弹出窗口。下面是不同操作系统下的对话过程:
微软视窗 10
MS:"嘘......是/"。connecttest.txt 那里?"
皮克 W:"是的、 200“.
MS: "OK, take me to /redirect“
皮克 W:"嗯,是的、 302请访问 http://pico.wireless/ 我们为您服务的地方 index.html“.
亚马逊 Fire Android 9
AMZ:"嘘......在哪里? /generate_204 那里?"
皮克 W:"默认情况下,我想说 204但我知道你真正想要的是 302 转入 http://pico.wireless/ (该页面显示 index.html,又名您的囚禁页面)"
配备 iOS 15 的苹果 iPhone 8
iPhone:"我很酷,所以我只是在寻找文件 /hotspot-detect.html“
皮克 W:"是的,去 http://pico.wireless/“
iPhone:"嗯,似乎与我要求的完全不同,但我相信你,所以我现在要去那里"。
响应代码 200:"OK",204:"No Content",302:"Found":"无内容",302:"找到"。
正如您所看到的,不同的设备会询问不同的路线和网页。如果您回答正确,它们就会触发弹出窗口。
以下是发送和接收所需内容的摘要:
Windows 10
网址 | 触发响应 |
www.msftconnecttest.com/ncsi.txt | 200 OK |
www.msftconnecttest.com/connecttest.txt | 200 OK |
www.msftconnecttest.com/redirect | 302 重定向(重定向至专属门户,如 index.html) |
安卓 9, 10
网址 | 触发响应 |
connectivitycheck.gstatic.com/generate_204 | 302 重定向(转至专属门户页面) |
其他安卓版本可能会查询其他 URL。我相信较新的安卓版本会有 /generate_204 作为备用。
这里有两个适用于旧版 Android 的资源:
https://lemariva.com/blog/2017/11/white-hacking-wemos-captive-portal-using-micropython
iOS 15
网址 | 触发响应 |
captive.apple.com/hotspot-detect.html | 200 OK(以网页响应) |
我的运行安卓 10 系统的三星 Note 9 最难破解。从表面上看,你可以按照典型的安卓模式进行操作,但可惜的是,一切都行不通!
我确实收到了 "需要登录 "的提示,但只有在将 DNS 更改为公共局域网 IP("10.0.0.0/8、172.16.0.0/12 或 192.168.0.0/16" 范围之外的 IP)之后才能收到提示。 请参阅此 Stack Exchange 评论。
但上述操作会破坏其他所有设备的捕获门户......
Pico W 专用门户的 Pimoroni Phew 库
Pimoroni's Phew 图书馆使创建一个专属门户网站变得容易得多,因为他们已经完成了所有繁重的工作。
首先,你需要下载程序库。我使用的是 0.0.3 版本 可在此处下载。
然后,解压缩文件并上传名为 呼 我个人使用的是 Thonny 集成开发环境,您可以 了解如何在此上传文件。
让我们对热点弹出窗口进行编码!
那么,让我先从 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")
需要说明的是,我是从凯文-麦卡勒(Kevin McAleer)那里借鉴了这段代码,并根据我们的目的进行了修改。如果你想观看凯文对工作原理的深入解释,请点击此处、 观看 YouTube 视频。
不过,请允许我简要介绍一下不同的部分。
有三个部分带有注释 "#android 重定向"、"#apple 重定向 "和 "# microsoft windows 重定向"。这些部分处理每个操作系统提出的测试,并作出正确的回应。
在响应结束时,它们将被重定向到 http://{DOMAIN}/,但苹果路由除外(因为凯文是这么写的,如果它没坏......)。
重定向到 DOMAIN(声明为 "pico.wireless")将为我们提供一个不那么难看的 URL。
因此,我们在地址栏上看到的不是 "www.msftconnecttest.com",而是 "pico.wireless"。当然,这也是您的企业专属门户网站需要注意的地方。
Pimoroni 呼,减少了您需要编写的代码
Phew 的美妙之处在于,与从头开始编写代码相比,您所编写的代码要少得多。
例如,如果您想在 Pico W 上启动 SoftAP,您可以编写类似这样的代码:
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
有了 Pimoroni's Phew,您的负担就减轻了:
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
如上图所示,创建路线非常简单。您只需使用 @server.route,并将路由和方法传入。然后用 要求 参数。
最后是 @server.catchall() 函数,它可以处理所有未指定的路由。
呼,超级简单!
index.html
这是一个非常简单的概念验证 index.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 上为企业建立专属门户所需的全部知识。
如果您有任何问题,请随时在下面的评论中告诉我们!
盗版盒子的理想替代品(虽然没有聊天功能和上传功能)。
这正是我想要的!
大部分情况下都能正常运行,但网站没有自己弹出,而是出现了错误:
2023-03-31 12:02:35 [info / 160kB] > GET /generate_204 (302 Found) [236ms]
未检索到任务异常
future: coro=
回溯(最近的一次调用)。
文件 "uasyncio/core.py",第 1 行,在 run_until_complete 中
文件 "phew/server.py",第 242 行,在 _handle_request 中
文件 "phew/server.py",第 161 行,在 _parse_headers 中
ValueError:需要超过 1 个值才能解包
不知道这是否与我的旧手机仍是 Android 6 有关。
如何编辑代码,将 HTML 代码包含在程序中?我试过了,但没有成功。
我发现程序流程非常混乱。
你好!我很高兴为你提供帮助!能否请您详细描述一下您的问题,并告诉我您使用的是哪台设备的自闭门户?
你好! AP 启动了,DNS 启动了,但网络服务器要么从未启动,要么要花很长时间(几分钟)才能启动。 您对原因有什么想法/线索/建议吗? 谢谢!
能否请您帮我理解一下,在成功连接到热点后,哪行代码会在客户端浏览器上执行/自动打开 "自封门户"?它似乎没有自动打开任何东西。我是从笔记本电脑连接的。
感谢您的精彩描述。
我想在同一个 AP 上添加第二个甚至第三个 SSID。Phew 有办法做到这一点吗?
有什么想法?
不,您需要为每个 ssid 使用一个 raspberry pi pico。