Managers/APConfigManager.cs

using Microsoft.Extensions.Logging;

using nanoFramework.Logging;

using nanoFramework.WebServer;

using System;

using System.Net;

using System.Threading;

namespace YeFanIoTTest.Managers

{

// AP配网状态枚举

public enum APConfigState

{

Idle, // 空闲

APConfiguring, // 正在配网

Connecting, // 正在连接

Configured, // 配网成功

Failed // 配网失败

}

// 配网完成事件参数

public class APConfigResultEventArgs : EventArgs

{

public bool Success { get; set; }

public string SSID { get; set; }

public string Message { get; set; }

}

internal class APConfigManager

{

// 日志记录器

private ILogger _logger;

// WIFI管理器(外部注入,不内部创建)

private WifiManager _wifiManager;

// Web服务器实例

private WebServer _webServer;

// 当前配网状态

public APConfigState CurrentState { get; private set; } = APConfigState.Idle;

// 配网完成事件(通知外部配网结果)

public event APConfigResultEventHandler OnConfigCompleted;

public delegate void APConfigResultEventHandler(object sender, APConfigResultEventArgs e);

// AP配网参数

private const string AP_SSID = "YF3300_ESP32S3"; // 热点名称

private const string AP_PASSWORD = "yf123456"; // 热点密码(WPA2需>=8)

private const string AP_IP = "192.168.4.1"; // AP网关IP

// Web服务器参数

private const int WEB_PORT = 80; // Web服务器端口

private const int CONFIG_TIMEOUT = 600000; // 配网超时时间(10分钟)

// 配网任务取消令牌

private CancellationTokenSource _configCts;

// 配网超时定时器

private Timer _timeoutTimer;

// 当前配网的SSID和密码(用于传递给WebServerController)

public static string PendingSSID { get; set; }

public static string PendingPassword { get; set; }

public static bool ConfigSubmitted { get; set; } = false;

// WifiManager实例(供WebServerController访问)

private static WifiManager _staticWifiManager;

// 获取WifiManager实例

public static WifiManager GetWifiManager()

{

return _staticWifiManager;

}

// 触发配网完成事件(由外部调用)

public void RaiseConfigCompleted(bool success, string ssid, string message)

{

if (OnConfigCompleted != null)

{

OnConfigCompleted(this, new APConfigResultEventArgs()

{

Success = success,

SSID = ssid,

Message = message

});

}

}

// 构造函数:注入WIFI管理器实例

public APConfigManager(WifiManager wifiManager)

{

if (wifiManager == null)

{

throw new ArgumentNullException(nameof(wifiManager));

}

_wifiManager = wifiManager;

_staticWifiManager = wifiManager; // 保存到静态字段

_logger = LogDispatcher.LoggerFactory.CreateLogger("APConfigManager");

}

#region 公共API

// 检查是否已有保存的WIFI配置

public bool HasSavedWifiConfig()

{

return _wifiManager.HasSavedConfig();

}

// 尝试使用已保存的配置连接WIFI

public bool TryConnectSavedWifiConfig()

{

if (_wifiManager.LoadCredentials(out string ssid, out string password))

{

_logger.LogInformation($"APConfigManager 尝试使用已保存的WIFI配置进行连接: {ssid}");

return _wifiManager.ConnectSTA(ssid, password, enableReconnect: true);

}

return false;

}

// 开始配网

public bool StartAPConfig()

{

if (CurrentState != APConfigState.Idle)

{

_logger.LogWarning("APConfigManager 当前AP状态不是空闲状态,无法开始配网");

return false;

}

_logger.LogInformation("APConfigManager 开始配网");

// 步骤一:启动AP热点

bool apStarted = _wifiManager.StartAP(AP_SSID, AP_PASSWORD, AP_IP);

if (!apStarted)

{

_logger.LogError("APConfigManager 启动AP热点失败");

CurrentState = APConfigState.Failed;

return false;

}

CurrentState = APConfigState.APConfiguring;

_logger.LogInformation($"APConfigManager AP热点已启动,热点名称:{AP_SSID}, IP:{AP_IP}");

// 步骤二:启动Web服务器

// 【重要】等待网络接口完全初始化后再启动Web服务器

Thread.Sleep(1000);

try

{

// 重置配网提交标志

ConfigSubmitted = false;

// 创建Web服务器实例

// 【重要】在AP模式下,必须显式指定绑定的IP地址,否则会绑定到错误的网络接口

_webServer = new WebServer(WEB_PORT, HttpProtocol.Http, IPAddress.Parse(AP_IP), new Type\[\] { typeof(WebServerController) });

_webServer.Start();

_logger.LogInformation($"APConfigManager Web服务器已启动,端口:{WEB_PORT},绑定IP:{AP_IP}");

// ========== 诊断信息:验证网络接口状态 ==========

try

{

var interfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();

foreach (var ni in interfaces)

{

if (ni.NetworkInterfaceType == System.Net.NetworkInformation.NetworkInterfaceType.WirelessAP)

{

_logger.LogInformation($"APConfigManager AP接口状态: {ni.IPv4Address}");

_logger.LogInformation($"APConfigManager AP接口类型: {ni.NetworkInterfaceType}");

}

}

}

catch (Exception ex)

{

_logger.LogWarning($"APConfigManager 获取网络接口信息失败: {ex.Message}");

}

}

catch (Exception e)

{

_logger.LogError($"APConfigManager 启动Web服务器失败: {e.Message}");

StopAPConfig();

return false;

}

// 步骤三:启动配网超时定时器

_configCts = new CancellationTokenSource();

_timeoutTimer = new Timer(OnTimeoutCallback, null, CONFIG_TIMEOUT, Timeout.Infinite);

_logger.LogInformation($"APConfigManager 请连接WIFI {AP_SSID},并访问 http://{AP_IP}");

_logger.LogInformation($"APConfigManager 配网超时定时器已启动,超时时间:{CONFIG_TIMEOUT / 1000} 秒");

return true;

}

// 停止AP配网(清理资源)

public void StopAPConfig()

{

_logger.LogInformation("APConfigManager 停止AP配网");

// 停止超时定时器

if (_timeoutTimer != null)

{

_timeoutTimer.Dispose();

_timeoutTimer = null;

}

// 取消配网任务

if (_configCts != null)

{

_configCts.Cancel();

_configCts.Dispose();

_configCts = null;

}

// 关闭Web服务器

if (_webServer != null)

{

_webServer.Stop();

_webServer.Dispose();

_webServer = null;

}

// 关闭AP热点

_wifiManager.StopAP();

CurrentState = APConfigState.Idle;

_logger.LogInformation("APConfigManager AP配网已停止");

}

// 处理配网提交(由WebServerController调用)

public void HandleConfigSubmit(string ssid, string password)

{

_logger.LogInformation($"APConfigManager 收到配网请求:{ssid}");

// 停止超时定时器

if (_timeoutTimer != null)

{

_timeoutTimer.Change(Timeout.Infinite, Timeout.Infinite);

}

// 停止Web服务器

if (_webServer != null)

{

_webServer.Stop();

}

CurrentState = APConfigState.Connecting;

// 尝试连接WIFI

bool connected = _wifiManager.ConnectSTA(ssid, password, enableReconnect: true);

if (connected)

{

// ========== 验证网络可达性 ==========

// 检查WiFi是否真的可以上网(通过DNS解析验证)

_logger.LogInformation("APConfigManager 正在验证网络可达性...");

bool networkReachable = _wifiManager.IsNetworkReachable();

if (!networkReachable)

{

_logger.LogWarning("APConfigManager WiFi已连接但网络不可达,请检查路由器是否连接外网");

// 仍然保存凭证,但提示用户网络可能不可用

}

else

{

_logger.LogInformation("APConfigManager 网络可达性验证成功,可以正常上网");

}

// ========== 保存WIFI凭证到Flash ==========

// 【测试时可注释以下2行,关闭持久化存储功能】

// _wifiManager.SaveCredentials(ssid, password);

_logger.LogInformation($"APConfigManager 已保存WIFI凭证:{ssid}");

CurrentState = APConfigState.Configured;

_logger.LogInformation($"APConfigManager 配网成功!SSID:{ssid}");

// 触发配网完成事件

if (OnConfigCompleted != null)

{

OnConfigCompleted(this, new APConfigResultEventArgs()

{

Success = true,

SSID = ssid,

Message = networkReachable ? "配网成功!网络可达" : "配网成功!但网络不可达,请检查路由器"

});

}

}

else

{

CurrentState = APConfigState.Failed;

_logger.LogError($"APConfigManager 配网失败!SSID:{ssid}");

// 触发配网失败事件

if (OnConfigCompleted != null)

{

OnConfigCompleted(this, new APConfigResultEventArgs()

{

Success = false,

SSID = ssid,

Message = "配网失败!"

});

}

// 重新启动AP配网

Thread.Sleep(2000);

CurrentState = APConfigState.Idle;

StartAPConfig();

}

}

#endregion

#region 私有方法

// 超时回调

private void OnTimeoutCallback(object state)

{

_logger.LogWarning("APConfigManager 配网超时!");

// 触发配网超时事件

if (OnConfigCompleted != null)

{

OnConfigCompleted(this, new APConfigResultEventArgs()

{

Success = false,

SSID = null,

Message = "配网超时!"

});

}

// 停止AP配网

StopAPConfig();

}

#endregion

}

}

相关推荐
剩下了什么7 小时前
float32 与 float64 精度陷阱:如何在 Go 中避免错误使用
开发语言·后端·golang
指尖时光.8 小时前
Three.js 超全入门综合案例
开发语言·javascript·ecmascript
暴力求解8 小时前
Linux网络---传输层协议TCP(二)
linux·服务器·开发语言·网络·tcp/ip
吴声子夜歌8 小时前
Java面试题——基础(一)
java·开发语言
小庞在加油9 小时前
WinDbg实战:QT/跨平台项目死锁与无响应问题排查指南
开发语言·qt·windbg·工具
Vae_Mars9 小时前
C#中的delegate委托
开发语言·c#
一直走下去-明10 小时前
简单的http抓包解包完整代码
开发语言·python
caimouse10 小时前
ReactOS 图形系统分析(51):元文件子系统 — metafile.c
c语言·开发语言
学习星球11 小时前
Solid.js 实战:拆解官方 RealWorld 项目
开发语言·javascript·vue.js
OPEN-F11 小时前
Python进阶教程:正则表达式进阶与文本处理
开发语言·python·正则表达式