Drivers/LedManager.cs using System;using System.Device.Gpio;using System.Threading;using Microsoft.Extensions.Logging;using nanoFramework.Logging;using YeFanIoTTest.Enums;using YFSoft.Hardware.YF3300_ESP32S3;namespace YeFanIoTTest.Drivers{// LED管理器 - 管理黄色LED网络状态和绿色LED配网状态public class LedManager : IDisposable{// 日志记录器private readonly ILogger _logger;// GPIO控制器外部注入private readonly GpioController _gpioController;// LED引脚private readonly GpioPin _yellowLedPin; // 黄色LED引脚网络状态指示private readonly GpioPin _greenLedPin; // 绿色LED引脚配网状态指示// 闪烁定时器private Timer _yellowLedTimer; // 黄色LED闪烁定时器private Timer _greenLedTimer; // 绿色LED闪烁定时器// 资源释放标志private bool _disposed;// 构造函数注入GPIO控制器public LedManager(GpioController gpioController){_gpioController gpioController ?? throw new ArgumentNullException(nameof(gpioController));_logger LogDispatcher.LoggerFactory.CreateLogger(LedManager);// 初始化LED引脚_yellowLedPin _gpioController.OpenPin(Mainboard.Pins.YellowLED, PinMode.Output);_greenLedPin _gpioController.OpenPin(Mainboard.Pins.GreenLED, PinMode.Output);// 初始化时关闭所有LEDTurnOffAll();_logger.LogInformation(LED manager initialized);}// 设置网络状态指示黄色LEDpublic void SetNetworkStatus(NetworkStatus status){StopYellowBlink();switch (status){case NetworkStatus.Connecting:// 常亮 - 正在连接网络_logger.LogDebug(Yellow LED: ON - Connecting to network);_yellowLedPin.Write(PinValue.High);break;case NetworkStatus.Connected:// 慢闪 - 网络正常_logger.LogDebug(Yellow LED: Slow blink - Network normal);StartYellowBlink(Mainboard.LEDTiming.NetworkNormal_On,Mainboard.LEDTiming.NetworkNormal_Off);break;case NetworkStatus.Disconnected:case NetworkStatus.Error:// 快闪 - 网络异常_logger.LogDebug(Yellow LED: Fast blink - Network error);StartYellowBlink(Mainboard.LEDTiming.NetworkError_On,Mainboard.LEDTiming.NetworkError_Off);break;}}// 设置配网状态指示绿色LEDpublic void SetConfigStatus(ConfigStatus status){StopGreenBlink();switch (status){case ConfigStatus.Configuring:// 常亮 - 正在配网_logger.LogDebug(Green LED: ON - Configuring);_greenLedPin.Write(PinValue.High);break;case ConfigStatus.Success:// 慢闪 - 配网成功_logger.LogDebug(Green LED: Slow blink - Config success);StartGreenBlink(Mainboard.LEDTiming.ConfigSuccess_On,Mainboard.LEDTiming.ConfigSuccess_Off);break;case ConfigStatus.Failed:// 快闪 - 配网失败_logger.LogDebug(Green LED: Fast blink - Config failed);StartGreenBlink(Mainboard.LEDTiming.ConfigFailed_On,Mainboard.LEDTiming.ConfigFailed_Off);break;case ConfigStatus.Normal:// 熄灭 - 正常运行_logger.LogDebug(Green LED: OFF - Normal operation);_greenLedPin.Write(PinValue.Low);break;}}// 启动黄色LED闪烁private void StartYellowBlink(int onMs, int offMs){StopYellowBlink();bool isOn false;_yellowLedTimer new Timer(_ {isOn !isOn;_yellowLedPin.Write(isOn ? PinValue.High : PinValue.Low);}, null, 0, isOn ? onMs : offMs);}// 停止黄色LED闪烁private void StopYellowBlink(){if (_yellowLedTimer ! null){_yellowLedTimer.Dispose();_yellowLedTimer null;}}// 启动绿色LED闪烁private void StartGreenBlink(int onMs, int offMs){StopGreenBlink();bool isOn false;_greenLedTimer new Timer(_ {isOn !isOn;_greenLedPin.Write(isOn ? PinValue.High : PinValue.Low);}, null, 0, isOn ? onMs : offMs);}// 停止绿色LED闪烁private void StopGreenBlink(){if (_greenLedTimer ! null){_greenLedTimer.Dispose();_greenLedTimer null;}}// 关闭所有LEDpublic void TurnOffAll(){_yellowLedPin.Write(PinValue.Low);_greenLedPin.Write(PinValue.Low);}// 释放资源public void Dispose(){if (!_disposed){StopYellowBlink();StopGreenBlink();_yellowLedPin?.Dispose();_greenLedPin?.Dispose();_disposed true;_logger.LogInformation(LED manager disposed);}}}}Managers/MqttClientManager.csusing System;using System.Collections;using System.Text;using Microsoft.Extensions.Logging;using nanoFramework.Logging;using nanoFramework.M2Mqtt;using nanoFramework.M2Mqtt.Messages;using YeFanIoTTest.Models;namespace YeFanIoTTest.Managers{// MQTT客户端管理器// 负责与叶帆物联网平台通信实现YFLink协议internal class MqttClientManager{private readonly ILogger _logger;private MqttClient _mqttClient;private bool _isConnected false;// MQTT连接参数private const string MqttServer iot.yfios.net;private const int MqttPort 1883;private const string ProjectId YFIoT_TEST;private const string ProductId YF3300_ESP32S3;private const string DeviceId YF3300_ESP32S301;private const string DeviceKey dxR99LCS7Uldc7KUnurFBeBi;// MQTT主题V1.3.0 去掉前导/以支持共享订阅private const string PropertyPostTopic {0}/{1}/{2}/property/post; // 属性上传private const string EventPostTopic {0}/{1}/{2}/event/post; // 事件上传private const string ServiceSendTopic {0}/{1}/{2}/service/send; // 服务下发private const string ServiceResultTopic {0}/{1}/{2}/service/result; // 服务响应// 事件收到服务下发public event ServiceReceivedEventHandler OnServiceReceived;// 服务下发事件委托public delegate void ServiceReceivedEventHandler(object sender, ServiceSendRequest request);// 属性是否已连接public bool IsConnected _isConnected;// 构造函数public MqttClientManager(){_logger LogDispatcher.LoggerFactory.CreateLogger(MqttClientManager);}// 连接到MQTT服务器public bool Connect(){try{_logger.LogInformation(Connecting to MQTT server...);// 创建MQTT客户端_mqttClient new MqttClient(MqttServer, MqttPort, false, null, null, MqttSslProtocols.None);// 设置回调_mqttClient.MqttMsgPublishReceived OnMessageReceived;_mqttClient.MqttMsgSubscribed OnSubscribed;_mqttClient.ConnectionClosed OnConnectionClosed;// 连接参数YFLink协议格式// clientId - 项目ID - 产品ID - 设备ID// userName - 项目ID 产品ID 设备ID// password - HMACSHA1(DeviceKey, clientId userName) 转为小写十六进制string clientId ${ProjectId}-{ProductId}-{DeviceId};string username ${ProjectId}{ProductId}{DeviceId};// 计算HMACSHA1密码string content clientId username;string password CalculateHmacSha1(content, DeviceKey).ToLower();_logger.LogInformation($MQTT ClientId: {clientId});_logger.LogInformation($MQTT Username: {username});_logger.LogInformation($MQTT Password: {password});// 连接服务器var result _mqttClient.Connect(clientId, username, password, false, 60);if (result MqttReasonCode.Success){_isConnected true;_logger.LogInformation($MQTT connected successfully, ClientId: {clientId});// 订阅服务下发主题SubscribeServiceTopic();return true;}else{_logger.LogError($MQTT connection failed, reason: {result});return false;}}catch (Exception ex){_logger.LogError($Failed to connect MQTT: {ex.Message});return false;}}// 断开连接public void Disconnect(){try{if (_mqttClient ! null _mqttClient.IsConnected){_mqttClient.Disconnect();_logger.LogInformation(MQTT disconnected);}_isConnected false;}catch (Exception ex){_logger.LogError($Failed to disconnect MQTT: {ex.Message});}}// 上传属性public bool PublishProperties(Hashtable properties){if (!_isConnected){_logger.LogWarning(MQTT not connected, cannot publish properties);return false;}try{// 构建属性上传请求var request new PropertyPostRequest{id GenerateMessageId(),timestamp GetCurrentTimestamp(),parameters properties};// 序列化为JSONstring json SerializeToJson(request);// 发布消息string topic string.Format(PropertyPostTopic, ProjectId, ProductId, DeviceId);_mqttClient.Publish(topic, Encoding.UTF8.GetBytes(json), null, null, MqttQoSLevel.AtLeastOnce, false);_logger.LogInformation($Properties published: {json});return true;}catch (Exception ex){_logger.LogError($Failed to publish properties: {ex.Message});return false;}}// 上传事件public bool PublishEvent(int eventType, int eventCode, string content){if (!_isConnected){_logger.LogWarning(MQTT not connected, cannot publish event);return false;}try{// 构建事件数据var eventData new EventData{type eventType,code eventCode,content content,time GetCurrentTimestamp()};// 构建事件上传请求var request new EventPostRequest{id GenerateMessageId(),timestamp GetCurrentTimestamp(),parameters new ArrayList { eventData }};// 序列化为JSONstring json SerializeToJson(request);// 发布消息string topic string.Format(EventPostTopic, ProjectId, ProductId, DeviceId);_mqttClient.Publish(topic, Encoding.UTF8.GetBytes(json), null, null, MqttQoSLevel.AtLeastOnce, false);_logger.LogInformation($Event published: {json});return true;}catch (Exception ex){_logger.LogError($Failed to publish event: {ex.Message});return false;}}// 订阅服务下发主题private void SubscribeServiceTopic(){try{string topic string.Format(ServiceSendTopic, ProjectId, ProductId, DeviceId);_mqttClient.Subscribe(new string[] { topic }, new MqttQoSLevel[] { MqttQoSLevel.AtLeastOnce });_logger.LogInformation($Subscribed to service topic: {topic});}catch (Exception ex){_logger.LogError($Failed to subscribe service topic: {ex.Message});}}// 消息接收回调private void OnMessageReceived(object sender, MqttMsgPublishEventArgs e){try{string topic e.Topic;string message Encoding.UTF8.GetString(e.Message, 0, e.Message.Length);_logger.LogInformation($Message received, Topic: {topic}, Message: {message});// 检查是否为服务下发主题string serviceTopic string.Format(ServiceSendTopic, ProjectId, ProductId, DeviceId);if (topic serviceTopic){// 解析服务下发请求var request DeserializeFromJsonServiceSendRequest(message);if (request ! null){// 触发事件OnServiceReceived?.Invoke(this, request);}}}catch (Exception ex){_logger.LogError($Error processing received message: {ex.Message});}}// 订阅成功回调private void OnSubscribed(object sender, MqttMsgSubscribedEventArgs e){_logger.LogInformation($Subscribed successfully, MessageId: {e.MessageId});}// 连接关闭回调private void OnConnectionClosed(object sender, EventArgs e){_isConnected false;_logger.LogWarning(MQTT connection closed);}// 生成消息IDprivate int GenerateMessageId(){var random new Random();return random.Next();}// 获取当前时间戳毫秒private long GetCurrentTimestamp(){return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds;}// 序列化为JSONYFLink协议格式private string SerializeToJson(object obj){// YFLink属性上传格式// {// id: 1234578,// timestamp: xxxxx,// params: {// H: 36.2,// T: 29.3,// I1: 0,// I2: 0,// Q1: 0// }// }if (obj is PropertyPostRequest propReq){var sb new StringBuilder();sb.Append({);sb.Append($\id\:{propReq.id},);sb.Append($\timestamp\:{propReq.timestamp},);sb.Append(\params\:{);bool first true;foreach (DictionaryEntry entry in propReq.parameters){if (!first) sb.Append(,);// 根据值类型决定是否需要引号和格式if (entry.Value is string){sb.Append($\{entry.Key}\:\{entry.Value}\);}else if (entry.Value is double){// 对double类型保留一位小数double value (double)entry.Value;sb.Append($\{entry.Key}\:{value:F1});}else{sb.Append($\{entry.Key}\:{entry.Value});}first false;}sb.Append(}});return sb.ToString();}return {};}// 从JSON反序列化简化版private T DeserializeFromJsonT(string json) where T : class{// 这里使用简化的JSON反序列化// 实际项目中应使用nanoFramework.Json库return null;}// 计算HMACSHA1YFLink协议要求的密码计算方法// content: ClientID UserName// key: DeviceKey// 注意nanoFramework只支持HMACSHA256 和 HMACSHA512这里使用自定义HMACSHA1实现private string CalculateHmacSha1(string content, string key){try{// 将key和content转换为字节数组byte[] keyBytes Encoding.UTF8.GetBytes(key);byte[] contentBytes Encoding.UTF8.GetBytes(content);// 使用自定义HMACSHA1实现byte[] hashBytes HmacSha1(keyBytes, contentBytes);// 转换为十六进制字符串return BytesToHexString(hashBytes);}catch (Exception ex){_logger.LogError($HMACSHA1 calculation failed: {ex.Message});return string.Empty;}}// 自定义HMACSHA1实现因为nanoFramework不支持HMACSHA1private byte[] HmacSha1(byte[] key, byte[] message){// HMAC算法步骤// 1. 如果key长度大于64字节先对key进行SHA1哈希// 2. 如果key长度小于64字节用0填充到64字节// 3. 计算inner padding: key XOR 0x36// 4. 计算outer padding: key XOR 0x5C// 5. 计算hash SHA1(outer_padding SHA1(inner_padding message))const int blockSize 64; // SHA1的块大小是64字节// 处理keybyte[] normalizedKey new byte[blockSize];if (key.Length blockSize){// Key太长先进行SHA1哈希byte[] keyHash Sha1(key);Array.Copy(keyHash, normalizedKey, keyHash.Length);}else{Array.Copy(key, normalizedKey, key.Length);}// 创建inner padding (key XOR 0x36)byte[] innerPadding new byte[blockSize];for (int i 0; i blockSize; i){innerPadding[i] (byte)(normalizedKey[i] ^ 0x36);}// 创建outer padding (key XOR 0x5C)byte[] outerPadding new byte[blockSize];for (int i 0; i blockSize; i){outerPadding[i] (byte)(normalizedKey[i] ^ 0x5C);}// 计算inner hash: SHA1(inner_padding message)byte[] innerData new byte[blockSize message.Length];Array.Copy(innerPadding, innerData, blockSize);Array.Copy(message, 0, innerData, blockSize, message.Length);byte[] innerHash Sha1(innerData);// 计算outer hash: SHA1(outer_padding inner_hash)byte[] outerData new byte[blockSize innerHash.Length];Array.Copy(outerPadding, outerData, blockSize);Array.Copy(innerHash, 0, outerData, blockSize, innerHash.Length);byte[] outerHash Sha1(outerData);return outerHash;}// 自定义SHA1实现private byte[] Sha1(byte[] data){// SHA1算法实现// 初始化哈希值uint h0 0x67452301;uint h1 0xEFCDAB89;uint h2 0x98BADCFE;uint h3 0x10325476;uint h4 0xC3D2E1F0;// 预处理填充数据int originalLength data.Length;int paddedLength ((originalLength 8) / 64 1) * 64;byte[] paddedData new byte[paddedLength];Array.Copy(data, paddedData, originalLength);paddedData[originalLength] 0x80; // 添加1后面跟着0// 添加原始长度位ulong bitLength (ulong)originalLength * 8;for (int i 0; i 8; i){paddedData[paddedLength - 8 i] (byte)(bitLength (56 - i * 8));}// 处理每个512位64字节块for (int blockStart 0; blockStart paddedLength; blockStart 64){// 将块分成16个32位字uint[] w new uint[80];for (int i 0; i 16; i){w[i] (uint)(paddedData[blockStart i * 4] 24 |paddedData[blockStart i * 4 1] 16 |paddedData[blockStart i * 4 2] 8 |paddedData[blockStart i * 4 3]);}// 扩展为80个字for (int i 16; i 80; i){w[i] LeftRotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);}// 初始化工作变量uint a h0;uint b h1;uint c h2;uint d h3;uint e h4;// 主循环for (int i 0; i 80; i){uint f, k;if (i 20){f (b c) | ((~b) d);k 0x5A827999;}else if (i 40){f b ^ c ^ d;k 0x6ED9EBA1;}else if (i 60){f (b c) | (b d) | (c d);k 0x8F1BBCDC;}else{f b ^ c ^ d;k 0xCA62C1D6;}uint temp LeftRotate(a, 5) f e k w[i];e d;d c;c LeftRotate(b, 30);b a;a temp;}// 添加工作变量到哈希值h0 a;h1 b;h2 c;h3 d;h4 e;}// 生成最终哈希值20字节byte[] hash new byte[20];hash[0] (byte)(h0 24);hash[1] (byte)(h0 16);hash[2] (byte)(h0 8);hash[3] (byte)h0;hash[4] (byte)(h1 24);hash[5] (byte)(h1 16);hash[6] (byte)(h1 8);hash[7] (byte)h1;hash[8] (byte)(h2 24);hash[9] (byte)(h2 16);hash[10] (byte)(h2 8);hash[11] (byte)h2;hash[12] (byte)(h3 24);hash[13] (byte)(h3 16);hash[14] (byte)(h3 8);hash[15] (byte)h3;hash[16] (byte)(h4 24);hash[17] (byte)(h4 16);hash[18] (byte)(h4 8);hash[19] (byte)h4;return hash;}// 32位左循环移位private uint LeftRotate(uint value, int bits){return (value bits) | (value (32 - bits));}// 字节数组转十六进制字符串private string BytesToHexString(byte[] bytes){var sb new StringBuilder();foreach (byte b in bytes){sb.Append(b.ToString(x2));}return sb.ToString();}}}