使用 IoT Edge 图像分类器改造 Wio Terminal 水果质量检测:从 HTTPS 云服务切换到本地 HTTP 边缘推理
2026/9/16 9:09:54 网站建设 项目流程

使用 IoT Edge 图像分类器改造 Wio Terminal 水果质量检测:从 HTTPS 云服务切换到本地 HTTP 边缘推理

【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners

本篇技术指南聚焦于 IoT-For-Beginners 制造(Manufacturing)项目中"边缘运行水果检测器"一课的核心实操环节:将运行在 Wio Terminal 上的fruit-quality-detector程序,从调用云端 Custom Vision 分类服务,改造为调用部署在本地 IoT Edge 设备上的图像分类器。读者将掌握 REST 接口切换、TLS 证书与 API 密钥移除、WiFi 客户端类型替换等完整的嵌入式改造方法,并理解边缘推理与云端推理在安全模型上的本质差异。

改造背景:从云分类切换到边缘分类

在上一课 2-check-fruit-from-device/wio-terminal-classify-image.md 中,Wio Terminal 通过 HTTPS 调用 Custom Vision 云服务完成水果(熟/生)分类:请求中需要携带CERTIFICATE(Microsoft Azure DigiCert Global Root G2 证书)用于建立 TLS 加密连接,还需要PREDICTION_KEY作为 Azure 资源的访问密钥,二者在 上一课的 config.h 中均有完整定义。

而本课的核心转变在于:图像分类模型已经被训练、导出、打包成容器并部署到本地的 IoT Edge 设备上(具体流程见本课主文档 README.md 与部署清单 deployment.json)。分类器在边缘设备上以 REST API 形式运行,使用的是HTTP 而非 HTTPS,因此:

  • 不再需要 TLS 证书(CERTIFICATE);
  • 不再需要云服务密钥(PREDICTION_KEY);
  • 不再需要安全 WiFi 客户端(WiFiClientSecure)。

边缘分类器的访问端点

IoT Edge 分类器的统一访问地址格式为:

http://<IP 地址或主机名>/image

其中<IP 地址或主机名>替换为运行 IoT Edge 的计算机的 IP 地址或主机名。例如,当 IoT Edge 与 Wio Terminal 处于同一局域网时,端点形如http://192.168.1.100/image。这是容器内 Flask 服务暴露在 80 端口的 REST 接口(可从iotedge logs ImageClassifier输出中的Running on http://0.0.0.0:80/得到印证,详见 README.md 的验证小节)。

改造任务:逐步切换客户端到 HTTP

第 1 步:打开项目

打开fruit-quality-detector应用项目(若尚未打开)。该项目的完整工程文件位于 code-classify/wio-terminal/fruit-quality-detector,工程基于 PlatformIO,目标板为seeed_wio_terminal(见 platformio.ini)。

第 2 步:清理 config.h 中的证书与密钥

图像分类器以 REST API 方式运行,使用 HTTP 而非 HTTPS,因此请求只需支持纯 HTTP 的 WiFi 客户端,证书不再需要。编辑 config.h:

  1. 删除CERTIFICATE常量(即从const char *CERTIFICATE ="-----END CERTIFICATE-----\r\n";的整段声明);
  2. 删除PREDICTION_KEY常量
  3. 更新PREDICTION_URL为边缘分类器地址。

改造后的config.h最终形态与仓库中已完成的代码一致,仅保留 WiFi 凭据与预测地址:

#pragma once #include <string> using namespace std; // WiFi credentials const char *SSID = "<SSID>"; const char *PASSWORD = "<PASSWORD>"; const char *PREDICTION_URL = "<URL>";

<URL>替换为你的分类器地址(即http://<IP 地址或主机名>/image)。对比改造前的 config.h 可以看到,除SSIDPASSWORDPREDICTION_URL外,还多出PREDICTION_KEY与整段CERTIFICATE,这正是本课需要清理的内容。

第 3 步:切换 include 指令

在 main.cpp 中,将 WiFi Client Secure 的包含指令改为标准 HTTP 版本:

#include <WiFiClient.h>

(改造前为#include <WiFiClientSecure.h>。)

第 4 步:切换客户端实例声明

将全局客户端声明改为 HTTP 版本:

WiFiClient client;

(改造前为WiFiClientSecure client;。)WiFiClient提供与 web 端点进行普通 HTTP 通信的能力;由于本地边缘分类器不走 TLS,不需要WiFiClientSecure的加密握手能力。

第 5 步:移除证书设置

connectWiFi函数中,找到并删除设置证书的行:

client.setCACert(CERTIFICATE);

改造后的connectWiFi仅负责连接 WiFi:

void connectWiFi() { while (WiFi.status() != WL_CONNECTED) { Serial.println("Connecting to WiFi.."); WiFi.begin(SSID, PASSWORD); delay(500); } Serial.println("Connected!"); }

第 6 步:移除预测密钥请求头

classifyImage函数中,删除设置预测密钥请求头的行:

httpClient.addHeader("Prediction-Key", PREDICTION_KEY);

改造后的classifyImage不再携带任何 Azure 鉴权信息:

void classifyImage(byte *buffer, uint32_t length) { HTTPClient httpClient; httpClient.begin(client, PREDICTION_URL); httpClient.addHeader("Content-Type", "application/octet-stream"); int httpResponseCode = httpClient.POST(buffer, length); if (httpResponseCode == 200) { String result = httpClient.getString(); DynamicJsonDocument doc(1024); deserializeJson(doc, result.c_str()); JsonObject obj = doc.as<JsonObject>(); JsonArray predictions = obj["predictions"].as<JsonArray>(); for(JsonVariant prediction : predictions) { String tag = prediction["tagName"].as<String>(); float probability = prediction["probability"].as<float>(); char buff[32]; sprintf(buff, "%s:\t%.2f%%", tag.c_str(), probability * 100.0); Serial.println(buff); } } httpClient.end(); }

httpClient.begin(client, PREDICTION_URL)将 HTTP 客户端绑定到普通的WiFiClient与边缘分类器地址上;POST 请求把相机采集到的 JPEG 字节流上传,响应中的predictions数组则被 ArduinoJson 解析后逐条输出到串口。

源码层面的印证:仓库中已完成改造的形态

本课仓库目录 code-classify/wio-terminal 中的代码即为改造完成的最终形态,可作为对照:

  • config.h:仅保留SSIDPASSWORDPREDICTION_URL三个常量,CERTIFICATEPREDICTION_KEY均已消失;
  • main.cpp:
    • 第 8 行为#include <WiFiClient.h>(HTTP 版客户端);
    • 第 15 行为WiFiClient client;
    • connectWiFi中无setCACert调用;
    • classifyImage中无Prediction-Key请求头。

从代码结构可以推断,图片采集链路与分类逻辑本身并未改变:buttonPressed()在检测到按钮 C(WIO_KEY_C)按下后调用camera.startCapture()等待captureReady(),随后通过camera.readImageToBuffer(&buffer, length)取得 JPEG 缓冲区并交给classifyImage。相机初始化为 JPEG 格式、OV2640 640x480 分辨率(见 camera.h 第 13 行Camera camera = Camera(JPEG, OV2640_640x480);及 main.cpp 第 13 行)。因此,本课改造的只是传输层与鉴权层,不涉及采集与推理结果解析

为什么边缘场景可以移除证书与密钥

这是一个值得理解的架构差异,而非简单的代码删减:

  • HTTPS + 证书:云服务(Custom Vision)是公网端点,必须通过 TLS 加密传输图像数据,因此客户端要内置受信任的 CA 证书(前课使用的正是 Microsoft Azure DigiCert Global Root G2 证书)。
  • HTTP + 本地网络:IoT Edge 分类器运行在你自己的局域网内,以普通 HTTP 暴露 REST 接口。正如本课 README 所指出的,这里不需要提供预测密钥——因为它不再是 Azure 资源,安全策略应基于内部网络的自身安全需求来配置,而不是依赖公网端点加 API 密钥。
  • 隐私与离线优势:图像数据不再离开本地网络,避免了每次推理的云端往返延迟与成本,也规避了敏感图像数据上传的隐私风险。代价是 Custom Vision 的 Predictions 标签页不再自动汇集这些边缘推理结果,若要继续改进模型,需要另行设计图像回传与人工再标注机制(详见 README.md 的 "Model retraining" 小节)。

烧录与运行验证

完成上述修改后,将代码编译烧录到 Wio Terminal,把相机对准某个水果并按下C 按钮,即可在串口监视器中看到分类结果:

Connecting to WiFi.. Connected! Image captured Image read to buffer with length 8200 ripe: 56.84% unripe: 43.16%

其中Image read to buffer with length 8200表示相机捕获的 JPEG 数据长度为 8200 字节,随后打印两个标签(ripe熟、unripe未熟)各自的概率百分比。概率来自边缘分类器返回的 JSONpredictions数组,probability为 0~1 的浮点数,乘以 100 后以两位小数百分比输出。

常见问题与衔接指引

  • 如果串口只显示连接失败:确认<URL>中的 IP 地址/主机名正确,且 Wio Terminal 与 IoT Edge 设备处于同一可达网络;可在运行 IoT Edge 的机器上先用curl验证分类器可用性,例如curl --location --request POST 'http://<IP 地址或主机名>/image' --header 'Content-Type: image/png' --data-binary '@<file_Name>'(详见 README.md 的 "test the image classifier" 小节)。
  • 为什么仍要部署清单:边缘端分类器模块ImageClassifier是通过az iot edge set-modules依据 deployment.json 部署到边缘设备的,其中将容器镜像<容器注册表名>.azurecr.io/classifier:v1映射到宿主机 80 端口;本课代码只负责"消费"该端口暴露的 REST 接口。
  • 使用其他 IoT 设备:本课同一套边缘分类器同样适用于单板计算机方案,对应指南为 single-board-computer.md;若在云端虚拟机搭建边缘设备,可参考 vm-iotedge.md。

至此,你的 Wio Terminal 水果质量分类程序已成功切换到本地 IoT Edge 推理,图像数据留在局域网内完成"熟/未熟"判断,为后续在工厂产线上部署实时、低延迟、隐私友好的视觉质检打下基础。

【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询