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);

// 初始化时关闭所有LED

TurnOffAll();

_logger.LogInformation("LED manager initialized");

}

// 设置网络状态指示(黄色LED)

public 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;

}

}

// 设置配网状态指示(绿色LED)

public 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;

}

}

// 关闭所有LED

public 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.cs

using 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

};

// 序列化为JSON

string 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 }

};

// 序列化为JSON

string 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 = DeserializeFromJson<ServiceSendRequest>(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");

}

// 生成消息ID

private int GenerateMessageId()

{

var random = new Random();

return random.Next();

}

// 获取当前时间戳(毫秒)

private long GetCurrentTimestamp()

{

return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds;

}

// 序列化为JSON(YFLink协议格式)

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 DeserializeFromJson<T>(string json) where T : class

{

// 这里使用简化的JSON反序列化

// 实际项目中应使用nanoFramework.Json库

return null;

}

// 计算HMACSHA1(YFLink协议要求的密码计算方法)

// 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不支持HMACSHA1)

private 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字节

// 处理key

byte\[\] normalizedKey = new byteblockSize;

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 byteblockSize;

for (int i = 0; i < blockSize; i++)

{

innerPaddingi = (byte)(normalizedKeyi ^ 0x36);

}

// 创建outer padding (key XOR 0x5C)

byte\[\] outerPadding = new byteblockSize;

for (int i = 0; i < blockSize; i++)

{

outerPaddingi = (byte)(normalizedKeyi ^ 0x5C);

}

// 计算inner hash: SHA1(inner_padding + message)

byte\[\] innerData = new byteblockSize + 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 byteblockSize + 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 bytepaddedLength;

Array.Copy(data, paddedData, originalLength);

paddedDataoriginalLength = 0x80; // 添加1后面跟着0

// 添加原始长度(位)

ulong bitLength = (ulong)originalLength * 8;

for (int i = 0; i < 8; i++)

{

paddedDatapaddedLength - 8 + i = (byte)(bitLength >> (56 - i * 8));

}

// 处理每个512位(64字节)块

for (int blockStart = 0; blockStart < paddedLength; blockStart += 64)

{

// 将块分成16个32位字

uint\[\] w = new uint80;

for (int i = 0; i < 16; i++)

{

wi = (uint)(paddedDatablockStart + i \* 4 << 24 |

paddedDatablockStart + i \* 4 + 1 << 16 |

paddedDatablockStart + i \* 4 + 2 << 8 |

paddedDatablockStart + i \* 4 + 3);

}

// 扩展为80个字

for (int i = 16; i < 80; i++)

{

wi = LeftRotate(wi - 3 ^ wi - 8 ^ wi - 14 ^ wi - 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 + wi;

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 byte20;

hash0 = (byte)(h0 >> 24);

hash1 = (byte)(h0 >> 16);

hash2 = (byte)(h0 >> 8);

hash3 = (byte)h0;

hash4 = (byte)(h1 >> 24);

hash5 = (byte)(h1 >> 16);

hash6 = (byte)(h1 >> 8);

hash7 = (byte)h1;

hash8 = (byte)(h2 >> 24);

hash9 = (byte)(h2 >> 16);

hash10 = (byte)(h2 >> 8);

hash11 = (byte)h2;

hash12 = (byte)(h3 >> 24);

hash13 = (byte)(h3 >> 16);

hash14 = (byte)(h3 >> 8);

hash15 = (byte)h3;

hash16 = (byte)(h4 >> 24);

hash17 = (byte)(h4 >> 16);

hash18 = (byte)(h4 >> 8);

hash19 = (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();

}

}

}

相关推荐
小樱花的樱花1 小时前
Linux 线程的创建
linux·c语言·开发语言
xiaoshuaishuai81 小时前
C# AI实现PR处理、单元测试
开发语言·c#·log4j
C++、Java和Python的菜鸟1 小时前
第7章 Java高级技术
java·开发语言
LONGZHIQIN2 小时前
C#基础复习笔记
开发语言·笔记·c#
可靠的仙人掌2 小时前
SAC(Soft Actor-Critic)算法底座
开发语言·算法·php
学逆向的2 小时前
汇编——数据存储模式
开发语言·汇编·网络安全
geovindu2 小时前
CSharp: Prototype Pattern
开发语言·后端·设计模式·.net·原型模式·创建型模式
天天进步20153 小时前
Python全栈项目--校园食堂点餐与推荐系统
开发语言·python
aaPIXa6223 小时前
C++模板元编程:编译期计算Fibonacci数列
java·开发语言·c++