Managers/WebServer.cs

using nanoFramework.WebServer;

using System;

using System.Diagnostics;

using System.IO;

using System.Text;

namespace YeFanIoTTest.Managers

{

// Web服务器控制器

// 处理AP配网的HTTP请求

// 【重要】必须是public类,否则WebServer无法实例化

public class WebServerController

{

// 静态APConfigManager实例引用

private static APConfigManager _apConfigManager;

// 设置APConfigManager实例(internal,因为APConfigManager是internal)

internal static void SetAPConfigManager(APConfigManager apConfigManager)

{

_apConfigManager = apConfigManager;

}

// ========== 配网页面路由 ==========

// GET / - 配网主页

Route("")

Method("GET")

public void GetIndex(WebServerEventArgs e)

{

Debug.WriteLine("WebServer ========== Received GET request ==========");

Debug.WriteLine($"WebServer Remote endpoint: {e.Context.Request.RemoteEndPoint}");

Debug.WriteLine($"WebServer Request URL: {e.Context.Request.RawUrl}");

// 直接输出HTML,不进行任何检查

string html = GetConfigPageHtml();

e.Context.Response.ContentType = "text/html";

WebServer.OutputAsStream(e.Context.Response, html);

Debug.WriteLine("WebServer Response sent successfully");

}

// POST /config - 处理配网表单提交

Route("config")

Method("POST")

public void PostConfig(WebServerEventArgs e)

{

try

{

// 解析表单数据

string body = GetRequestBody(e);

// 解析SSID和密码

string ssid = ParseFormField(body, "ssid");

string password = ParseFormField(body, "password");

if (string.IsNullOrEmpty(ssid) || string.IsNullOrEmpty(password))

{

string errorHtml = GetErrorPageHtml("SSID和密码不能为空!");

e.Context.Response.ContentType = "text/html";

WebServer.OutputAsStream(e.Context.Response, errorHtml);

return;

}

// ========== 调用APConfigManager处理配网 ==========

if (_apConfigManager == null)

{

string errorHtml = GetErrorPageHtml("系统错误:APConfigManager未初始化");

e.Context.Response.ContentType = "text/html";

WebServer.OutputAsStream(e.Context.Response, errorHtml);

return;

}

// 调用HandleConfigSubmit方法处理配网

// 该方法会:连接WiFi、检查网络可达性、触发OnConfigCompleted事件

_apConfigManager.HandleConfigSubmit(ssid, password);

// 根据配网结果显示页面

// 注意:HandleConfigSubmit已经处理了所有逻辑,这里只需要显示结果页面

// 由于HandleConfigSubmit是同步的,我们可以直接检查CurrentState

// 等待配网完成(最多等待10秒)

int waitCount = 0;

while (_apConfigManager.CurrentState == APConfigState.Connecting && waitCount < 100)

{

System.Threading.Thread.Sleep(100);

waitCount++;

}

// 根据配网结果显示页面

if (_apConfigManager.CurrentState == APConfigState.Configured)

{

// 配网成功

string successHtml = GetSuccessPageHtml(ssid);

e.Context.Response.ContentType = "text/html";

WebServer.OutputAsStream(e.Context.Response, successHtml);

}

else if (_apConfigManager.CurrentState == APConfigState.Failed)

{

// 配网失败

string errorHtml = GetErrorPageHtml("WiFi连接失败,请检查SSID和密码是否正确");

e.Context.Response.ContentType = "text/html";

WebServer.OutputAsStream(e.Context.Response, errorHtml);

}

else

{

// 其他状态(超时等)

string errorHtml = GetErrorPageHtml("配网超时,请重试");

e.Context.Response.ContentType = "text/html";

WebServer.OutputAsStream(e.Context.Response, errorHtml);

}

}

catch (Exception ex)

{

string errorHtml = GetErrorPageHtml("配网失败:" + ex.Message);

e.Context.Response.ContentType = "text/html";

WebServer.OutputAsStream(e.Context.Response, errorHtml);

}

}

// GET /scan - 扫描WiFi网络(AP模式下不支持)

Route("scan")

Method("GET")

public void GetScan(WebServerEventArgs e)

{

// AP模式下无法扫描WiFi网络

string jsonResult = "{\"success\":false,\"message\":\"AP模式下不支持WiFi扫描,请手动输入WiFi名称\"}";

e.Context.Response.ContentType = "application/json";

WebServer.OutputAsStream(e.Context.Response, jsonResult);

}

// ========== 辅助方法 ==========

// 获取请求体

private string GetRequestBody(WebServerEventArgs e)

{

try

{

var request = e.Context.Request;

// 获取请求体长度

long contentLength = request.ContentLength64;

if (contentLength == 0)

{

return string.Empty;

}

// 读取请求体

byte\[\] buffer = new byte(int)contentLength;

request.InputStream.Read(buffer, 0, (int)contentLength);

return Encoding.UTF8.GetString(buffer, 0, (int)contentLength);

}

catch (Exception)

{

return string.Empty;

}

}

// 解析表单字段

private static string ParseFormField(string body, string fieldName)

{

try

{

// 格式: ssid=MyWiFi&password=12345678

string searchPattern = fieldName + "=";

int startIndex = body.IndexOf(searchPattern);

if (startIndex < 0)

{

return string.Empty;

}

startIndex += searchPattern.Length;

int endIndex = body.IndexOf('&', startIndex);

if (endIndex < 0)

{

endIndex = body.Length;

}

string value = body.Substring(startIndex, endIndex - startIndex);

// URL解码

return UrlDecode(value);

}

catch

{

return string.Empty;

}

}

// URL解码

private static string UrlDecode(string value)

{

// 处理 %XX 格式的编码和 + 号

StringBuilder result = new StringBuilder();

for (int i = 0; i < value.Length; i++)

{

if (valuei == '+')

{

// + 号转换为空格

result.Append(' ');

}

else if (valuei == '%' && i + 2 < value.Length)

{

// 解析十六进制值

string hex = value.Substring(i + 1, 2);

byte b = HexToByte(hex);

if (b > 0)

{

result.Append((char)b);

i += 2;

}

else

{

result.Append(valuei);

}

}

else

{

result.Append(valuei);

}

}

return result.ToString();

}

// 十六进制字符串转字节

private static byte HexToByte(string hex)

{

try

{

byte high = HexCharToValue(hex0);

byte low = HexCharToValue(hex1);

return (byte)((high << 4) | low);

}

catch

{

return 0;

}

}

// 十六进制字符转数值

private static byte HexCharToValue(char c)

{

if (c >= '0' && c <= '9')

{

return (byte)(c - '0');

}

else if (c >= 'A' && c <= 'F')

{

return (byte)(c - 'A' + 10);

}

else if (c >= 'a' && c <= 'f')

{

return (byte)(c - 'a' + 10);

}

return 0;

}

// ========== HTML页面模板 ==========

// 配网主页HTML

private static string GetConfigPageHtml()

{

string html = "<!DOCTYPE html>";

html += "<html><head>";

html += "<meta charset=\"UTF-8\">";

html += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">";

html += "<title>YF3300-ESP32S3 WiFi配网</title>";

html += "<style>";

html += "body{font-family:Arial;margin:20px;background:#f0f0f0;}";

html += ".container{max-width:400px;margin:0 auto;background:white;padding:20px;border-radius:10px;}";

html += "h1{color:#333;text-align:center;}";

html += ".form-group{margin-bottom:15px;}";

html += "label{display:block;margin-bottom:5px;color:#666;}";

html += "input{width:100%;padding:10px;border:1px solid #ddd;border-radius:5px;box-sizing:border-box;}";

html += "button{width:100%;padding:12px;background:#007bff;color:white;border:none;border-radius:5px;font-size:16px;cursor:pointer;}";

html += ".footer{text-align:center;margin-top:20px;color:#999;font-size:12px;}";

html += ".tip{background:#fff3cd;border:1px solid #ffc107;padding:10px;border-radius:5px;margin-bottom:15px;font-size:14px;}";

html += "</style></head><body>";

html += "<div class=\"container\">";

html += "<h1>YF3300-ESP32S3 WiFi配网</h1>";

html += "<div class=\"tip\">请输入您要连接的WiFi名称和密码</div>";

html += "<form action=\"/config\" method=\"POST\">";

html += "<div class=\"form-group\">";

html += "<label>WiFi名称 (SSID)</label>";

html += "<input type=\"text\" name=\"ssid\" placeholder=\"请输入WiFi名称\" required>";

html += "</div>";

html += "<div class=\"form-group\">";

html += "<label>WiFi密码</label>";

html += "<input type=\"password\" name=\"password\" placeholder=\"请输入WiFi密码\" required>";

html += "</div>";

html += "<button type=\"submit\">开始配网</button>";

html += "</form>";

html += "<div class=\"footer\">YF3300-ESP32S3 v1.0</div>";

html += "</div></body></html>

相关推荐
LearnYard12 小时前
自然语言驱动的数据图表生成:几款工具功能对比实践
数据库·百度·powerpoint
MindUp15 小时前
告别排版焦虑:从 PPT 模板到 AI 生成工具的个人使用体验与效率对比
人工智能·powerpoint
fo安方3 天前
视频——工具——视频——ppt——AI生成ppt
人工智能·powerpoint
E_ICEBLUE4 天前
Python 办公自动化:将 PowerPoint (PPT/PPTX) 转换为 PDF 【全面指南】
python·pdf·powerpoint
皮皮虾❀4 天前
千问办公+Office一站式生成+原生编辑一体化实战:从“AI生成文档格式错乱”到“PPT/Word/Excel直接出成品可商用”的交付型AI落地路径
人工智能·word·powerpoint
Claire_885 天前
PPTX排版美化实测:三款AI工具对内容解析与导出编辑性的影响
powerpoint
LearnYard5 天前
年中汇报 PPT 制作,我的 AI 辅助工具横向测评与选型建议
人工智能·powerpoint
AI分享猿5 天前
从大纲到成稿:百智云PPT如何用“一段文字“驱动整套演示文稿
ai·powerpoint·ppt
Claire_886 天前
基于知识图谱构建的学习资料分类整理方案:以多模态检索与智能生成为例
人工智能·powerpoint
绎奇PPT7 天前
紧扣评审评分标准 打造原创探索计划高分PPT
信息可视化·powerpoint·ppt