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

}

}

相关推荐
小白学大数据25 分钟前
Codex 里的 GPT 6 Astra、GPT 5.6 Sol、Terra、Luna 怎么选
开发语言·gpt·microsoft
l1t2 小时前
DeepSeek 4.1总结的Tom Lane 谈塑造 Postgres 三十年历程的架构决策
开发语言·数据库·postgresql·架构
djarmy8 小时前
MAIN.c(1): warning C318: can’t open file ‘STC8G.H’ 报错 解决 分析
c语言·开发语言·mongodb
HEJOO98 小时前
深入理解 Java volatile 关键字:原理、用法与常见误区
java·开发语言·spring
曹牧8 小时前
Java:no content to map due to end of input
java·开发语言
梦梦代码精8 小时前
《回收租赁系统技术选型避坑指南:业务闭环与二开自由度详解》
开发语言·低代码·docker·开源·代码规范
隔窗听雨眠8 小时前
记一次SQL Server数据库性能分析:从CPU100%到单配置修复的完整诊断
开发语言·数据库·php
David猪大卫9 小时前
【C++修炼】智能指针使用及原理
开发语言·c++·经验分享·笔记·学习·考研·面试
charlie1145141919 小时前
现代Qt开发之图像处理进阶:像素操作与格式转换
开发语言·图像处理·qt
李永奉9 小时前
中科蓝讯SDK开发-BT893x 面条耳机连接vivo手机后连接APP端,最后手机端设置页面手动断开蓝牙连接,此时耳机端假断开
c语言·开发语言·嵌入式硬件·物联网·智能手机·电脑