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

}

}

相关推荐
拳里剑气1 小时前
C++算法:优先级队列
开发语言·c++·算法·优先级队列
小七在进步1 小时前
数据结构:用队列实现栈
开发语言·数据结构
从零开始的代码生活_2 小时前
C++ 模板入门:函数模板、类模板与实例化机制
开发语言·c++·后端
luj_176810 小时前
残熵算法实时化三大瓶颈突破
c语言·开发语言·网络·经验分享·算法
不听话坏10 小时前
Ignition篇(下 一) 动态执行前的事情
开发语言·前端·javascript
likeyi0710 小时前
require 和 import的区别
开发语言·前端
远离UE411 小时前
UE5 compute shader 原子加
开发语言·c++·ue5
C+-C资深大佬11 小时前
C++ 显式类型转换详解:static_cast、dynamic_cast、const_cast、reinterpret_cast
开发语言·c++
KaMeidebaby12 小时前
卡梅德生物技术快报|抗体亲和力成熟工业化调控新机制:差异性浆细胞增殖工艺优化思路
java·开发语言·人工智能·算法·机器学习·架构·spark