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