【YFIOs】用C#开发硬件之设备上云
·
将YF3300-ESP32S3设备数据上传到叶帆物联网平台需要使用 YFLink 协议通过 MQTT 进行通信。本章以完整项目 YeFanIoTTest 为例,介绍从设备初始化到数据上传的完整实现。
NuGet 软件包
| 包名 | 版本 | 用途 |
|---|---|---|
nanoFramework.CoreLibrary |
1.17.11 | 基础运行时(System 命名空间) |
nanoFramework.Hardware.Esp32 |
1.6.37 | ESP32 引脚功能配置(I2C/SPI/UART) |
nanoFramework.Iot.Device.DhcpServer |
1.2.938 | AP 模式 DHCP 服务器 |
nanoFramework.Logging |
1.1.161 | 日志记录(ILogger) |
nanoFramework.M2Mqtt |
5.1.212 | MQTT 客户端(连接叶帆物联平台) |
nanoFramework.Networking.Sntp |
1.6.42 | NTP 时间同步 |
nanoFramework.System.Collections |
1.5.67 | Hashtable / ArrayList(属性上传) |
nanoFramework.System.Device.Gpio |
1.1.57 | GPIO 控制(LED/按钮/继电器/数字输入) |
nanoFramework.System.Device.I2c |
1.1.29 | I2C 通信(SHT30 温湿度传感器) |
nanoFramework.System.Device.Wifi |
1.5.141 | WiFi STA/AP 管理 |
nanoFramework.System.Math |
1.5.116 | 数学运算(指数退避重连) |
nanoFramework.System.Net |
1.11.50 | DNS 解析(网络可达性检测) |
nanoFramework.System.Net.Http.Server |
1.5.204 | Web 服务器(配网页面) |
nanoFramework.System.Text |
1.3.42 | StringBuilder / UTF-8 编码 |
nanoFramework.System.Threading |
1.1.52 | 线程/定时器 |
nanoFramework.WebServer |
1.2.140 | WebServer 路由框架(属性路由) |
系统架构
┌─────────────────────────────────────────────────────────┐ |
|
│ YF3300-ESP32S3 设备 │ |
|
│ │ |
|
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │ |
|
│ │ SHT30 │ │ 继电器 │ │ 数字输入 │ │ BOOT │ │ |
|
│ │ 温湿度 │ │ GPIO48 │ │ GPIO21/47│ │ GPIO0 │ │ |
|
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬────┘ │ |
|
│ │ I2C │ GPIO │ GPIO │ GPIO │ |
|
│ ┌────▼──────────────▼────────────▼──────────────▼─────┐ │ |
|
│ │ 驱动层 (Drivers/) │ │ |
|
│ │ Sht30Sensor │ RelayDriver │ DigitalInputDriver │ │ |
|
│ │ ButtonDriver│ LedManager │ │ |
|
│ └────────────────────────┬────────────────────────────┘ │ |
|
│ │ │ |
|
│ ┌────────────────────────▼────────────────────────────┐ │ |
|
│ │ 管理层 (Managers/) │ │ |
|
│ │ MqttClientManager ←→ WifiManager ←→ APConfigManager│ │ |
|
│ │ NtpTimeManager │ ConfigurationManager │ │ |
|
│ └────────────────────────┬────────────────────────────┘ │ |
|
│ │ MQTT (YFLink协议) │ |
|
└───────────────────────────┼──────────────────────────────┘ |
|
│ |
|
┌────────▼────────┐ |
|
│ 叶帆物联网平台 │ |
|
│ iot.yfios.net │ |
|
│ MQTT:1883 │ |
|
└─────────────────┘ |
启动流程(12步初始化)
程序在 Main() 中按顺序执行12个步骤完成系统初始化:
| 步骤 | 组件 | GPIO/接口 | 说明 |
|---|---|---|---|
| 1 | Logger | - | 初始化 DebugLoggerFactory 日志系统 |
| 2 | GPIO | - | 创建 GpioController 实例 |
| 3 | LED | GPIO39/40 | 黄色(网络状态) + 绿色(配网状态) |
| 4 | Relay | GPIO48 | 1路继电器输出驱动 |
| 5 | Digital Input | GPIO21/47 | 2路开关量输入,回调模式 |
| 6 | SHT30 | I2C(17/18) | 温湿度传感器,地址0x44 |
| 7 | Button | GPIO0 | BOOT按钮,短按切换继电器/长按配网 |
| 8 | Configuration | - | WiFi凭证读写的配置管理器 |
| 9 | WiFi Manager | - | STA/AP双模式WiFi管理 |
| 10 | WiFi Connect | - | 加载配置连接WiFi,成功后初始化NTP |
| 11 | AP Config | - | AP配网管理器,含Web服务器 |
| 12 | MQTT Connect | - | 连接叶帆物联网平台 |
主循环逻辑
┌──────────────┐ |
|
│ counter++ │ |
|
└──────┬───────┘ |
|
│ |
|
▼ |
|
┌──────────────┐ 每5秒读取一次 |
|
│ 读取传感器 │◄── NTP时间 / 温湿度 / 数字输入 / 继电器状态 |
|
└──────┬───────┘ |
|
│ |
|
▼ |
|
┌──────────────┐ counter % 6 == 0 (约30秒) |
|
│ 是否上传? │─── NO ──► Sleep(5000ms) ──► 循环 |
|
└──────┬───────┘ |
|
│ YES |
|
▼ |
|
┌──────────────┐ |
|
│ UploadData │ 构建属性Hashtable → MQTT发布 |
|
│ ToCloud() │ 属性: H(湿度) T(温度) I1 I2 Q1 |
|
└──────────────┘ |
核心代码详解
1. 硬件引脚定义 (Hardware/YF3300_ESP32S3.cs)
Hardware/YF3300_ESP32S3.cs
using System; |
|
namespace YFSoft.Hardware.YF3300_ESP32S3 |
|
{ |
|
public static class CPU |
|
{ |
|
public static class Pins |
|
{ |
|
// GPIO 0-48 全部定义 |
|
public const int GPIO0 = 0; |
|
public const int GPIO9 = 9; // RS485 TX |
|
public const int GPIO10 = 10; // RS485 RX |
|
public const int GPIO11 = 11; // RS232 TX |
|
public const int GPIO12 = 12; // RS232 RX |
|
public const int GPIO17 = 17; // I2C SDA |
|
public const int GPIO18 = 18; // I2C SCL |
|
public const int GPIO21 = 21; // 开关量输入1 |
|
public const int GPIO39 = 39; // 绿色LED |
|
public const int GPIO40 = 40; // 黄色LED |
|
public const int GPIO47 = 47; // 开关量输入2 |
|
public const int GPIO48 = 48; // 继电器1 |
|
} |
|
} |
|
public static class Mainboard |
|
{ |
|
public static class Pins |
|
{ |
|
public const int YellowLED = CPU.Pins.GPIO40; // 网络状态 |
|
public const int GreenLED = CPU.Pins.GPIO39; // 配网状态 |
|
public const int BOOT = CPU.Pins.GPIO0; |
|
public const int I1 = CPU.Pins.GPIO21; |
|
public const int I2 = CPU.Pins.GPIO47; |
|
public const int Q1 = CPU.Pins.GPIO48; |
|
} |
|
public static class RS485 |
|
{ |
|
public const string PortName = "COM1"; |
|
public const int TxPin = CPU.Pins.GPIO9; |
|
public const int RxPin = CPU.Pins.GPIO10; |
|
} |
|
public static class I2C |
|
{ |
|
public const int BusId = 1; |
|
public const int SdaPin = CPU.Pins.GPIO17; |
|
public const int SclPin = CPU.Pins.GPIO18; |
|
} |
|
} |
|
// LED闪烁时序定义(毫秒) |
|
public static class LEDTiming |
|
{ |
|
// 黄色LED - 网络状态 |
|
public const int NetworkConnecting_On = 0; // 常亮 |
|
public const int NetworkNormal_On = 500; // 慢闪 |
|
public const int NetworkNormal_Off = 1500; |
|
public const int NetworkError_On = 200; // 快闪 |
|
public const int NetworkError_Off = 200; |
|
// 绿色LED - 配网状态 |
|
public const int ConfigAP_On = 0; // 常亮(配网中) |
|
public const int ConfigSuccess_On = 500; // 慢闪(成功) |
|
public const int ConfigFailed_On = 200; // 快闪(失败) |
|
} |
|
// 系统配置常量 |
|
public static class SystemConfig |
|
{ |
|
public const int WiFiConnectTimeout = 15000; // WiFi连接超时(ms) |
|
public const int WiFiReconnectInterval = 5000; // 重连间隔(ms) |
|
public const int MqttKeepAliveInterval = 60; // MQTT心跳(s) |
|
public const string APSSID = "YF3300_ESP32S3"; |
|
public const string APPassword = "yf123456"; |
|
public const string APIP = "192.168.4.1"; |
|
public const int APConfigTimeout = 600000; // 配网超时(10分钟) |
|
public const int SensorReadInterval = 30000; // 传感器读取间隔 |
|
public const int DataUploadInterval = 30000; // 数据上传间隔 |
|
} |
|
} |
2. YFLink 协议模型 (Models/YFLinkModels.cs)
YFLink协议使用JSON格式通过MQTT通信,所有请求都包含 id、ver(版本号1.3.0)、timestamp 三个基础字段。
Models/YFLinkModels.cs
using System.Collections; |
|
namespace YeFanIoTTest.Models |
|
{ |
|
// 基础请求/响应 |
|
public class YFLinkRequest |
|
{ |
|
public int id { get; set; } // 消息ID |
|
public string ver { get; set; } = "1.3.0"; // 协议版本 |
|
public long timestamp { get; set; } // Unix毫秒时间戳 |
|
} |
|
public class YFLinkResponse |
|
{ |
|
public int id { get; set; } |
|
public int code { get; set; } // 200=成功 |
|
public string message { get; set; } |
|
} |
|
// ★ 属性上传 |
|
public class PropertyPostRequest : YFLinkRequest |
|
{ |
|
public Hashtable parameters { get; set; } // 属性键值对 |
|
} |
|
// 事件上传 |
|
public class EventPostRequest : YFLinkRequest |
|
{ |
|
public ArrayList parameters { get; set; } // 事件数据列表 |
|
} |
|
public class EventData |
|
{ |
|
public int type { get; set; } // 0-信息 1-告警 2-故障 |
|
public int code { get; set; } // 事件编码 |
|
public string content { get; set; } // 事件内容(≤1024字节) |
|
public long time { get; set; } // 事件时间戳 |
|
} |
|
// 服务下发(云端→设备) |
|
public class ServiceSendRequest : YFLinkRequest |
|
{ |
|
public int serviceType { get; set; } // 0-命令 1-参数 |
|
public ServiceParams parameters { get; set; } |
|
} |
|
public class ServiceParams |
|
{ |
|
public string command { get; set; } |
|
public string parameter { get; set; } |
|
} |
|
// NTP校时 |
|
public class NtpRequest : YFLinkRequest |
|
{ |
|
public NtpParams parameters { get; set; } |
|
} |
|
public class NtpParams |
|
{ |
|
public long deviceSendTime { get; set; } |
|
} |
|
public class NtpResponse : YFLinkResponse |
|
{ |
|
public NtpResponseParams parameters { get; set; } |
|
} |
|
public class NtpResponseParams |
|
{ |
|
public long deviceSendTime { get; set; } |
|
public long serverRecvTime { get; set; } |
|
public long serverSendTime { get; set; } |
|
} |
|
} |
3. MQTT 连接与YFLink认证 (Managers/MqttClientManager.cs)
这是与叶帆物联网平台通信的核心代码,包含YFLink协议的三元组认证(HMAC-SHA1签名)。
3.1 MQTT连接参数
// MQTT服务器 |
|
private const string MqttServer = "iot.yfios.net"; |
|
private const int MqttPort = 1883; |
|
// YFLink三元组 |
|
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"; // 服务下发 |
3.2 HMAC-SHA1 认证算法
认证公式:
clientId = "{项目ID}-{产品ID}-{设备ID}" |
|
userName = "{项目ID}&{产品ID}&{设备ID}" |
|
password = HMAC-SHA1(DeviceKey, clientId + userName).toLowerCase(hex) |
Managers/MqttClientManager.cs - Connect方法
public bool Connect() |
|
{ |
|
// clientId: YFIoT_TEST-YF3300_ESP32S3-YF3300_ESP32S301 |
|
// userName: YFIoT_TEST&YF3300_ESP32S3&YF3300_ESP32S301 |
|
// password: HMAC-SHA1签名 → 小写十六进制 |
|
string clientId = $"{ProjectId}-{ProductId}-{DeviceId}"; |
|
string username = $"{ProjectId}&{ProductId}&{DeviceId}"; |
|
string password = CalculateHmacSha1(clientId + username, DeviceKey).ToLower(); |
|
_mqttClient = new MqttClient(MqttServer, MqttPort, false, null, null, MqttSslProtocols.None); |
|
// 注册回调 |
|
_mqttClient.MqttMsgPublishReceived += OnMessageReceived; |
|
_mqttClient.ConnectionClosed += OnConnectionClosed; |
|
var result = _mqttClient.Connect(clientId, username, password, false, 60); |
|
if (result == MqttReasonCode.Success) |
|
{ |
|
SubscribeServiceTopic(); // 订阅服务下发主题 |
|
return true; |
|
} |
|
return false; |
|
} |
3.3 属性上传
属性上传使用自定义JSON序列化(nanoFramework的 System.Text.Json 功能有限):
public bool PublishProperties(Hashtable properties) |
|
{ |
|
var request = new PropertyPostRequest |
|
{ |
|
id = GenerateMessageId(), |
|
timestamp = GetCurrentTimestamp(), |
|
parameters = properties // { "H":36.2, "T":29.3, "I1":0, "I2":0, "Q1":0 } |
|
}; |
|
string json = SerializeToJson(request); |
|
string topic = string.Format(PropertyPostTopic, ProjectId, ProductId, DeviceId); |
|
_mqttClient.Publish(topic, Encoding.UTF8.GetBytes(json), null, null, |
|
MqttQoSLevel.AtLeastOnce, false); |
|
return true; |
|
} |
上传的JSON格式:
{ |
|
"id": 1234578, |
|
"timestamp": 1716355200000, |
|
"params": { |
|
"H": 36.2, |
|
"T": 29.3, |
|
"I1": 0, |
|
"I2": 0, |
|
"Q1": 0 |
|
} |
|
} |
3.4 HMAC-SHA1 完整实现
Managers/MqttClientManager.cs - HMAC-SHA1自实现
// HMAC-SHA1算法(RFC 2104) |
|
private byte[] HmacSha1(byte[] key, byte[] message) |
|
{ |
|
const int blockSize = 64; // SHA1块大小 |
|
// 1. 规范化密钥(>64字节则先SHA1哈希) |
|
byte[] normalizedKey = new byte[blockSize]; |
|
if (key.Length > blockSize) |
|
Array.Copy(Sha1(key), normalizedKey, 20); |
|
else |
|
Array.Copy(key, normalizedKey, key.Length); |
|
// 2. 计算inner/outer padding |
|
byte[] innerPadding = new byte[blockSize]; |
|
byte[] outerPadding = new byte[blockSize]; |
|
for (int i = 0; i < blockSize; i++) |
|
{ |
|
innerPadding[i] = (byte)(normalizedKey[i] ^ 0x36); |
|
outerPadding[i] = (byte)(normalizedKey[i] ^ 0x5C); |
|
} |
|
// 3. HMAC = SHA1(outer_padding + SHA1(inner_padding + message)) |
|
byte[] innerHash = Sha1(Concat(innerPadding, message)); |
|
return Sha1(Concat(outerPadding, innerHash)); |
|
} |
|
// SHA1算法(FIPS 180-4) |
|
private byte[] Sha1(byte[] data) |
|
{ |
|
uint h0 = 0x67452301, h1 = 0xEFCDAB89, h2 = 0x98BADCFE, |
|
h3 = 0x10325476, h4 = 0xC3D2E1F0; |
|
// 填充 → 分块(64字节) → 80轮压缩 → 输出20字节 |
|
// ... (完整实现见项目源码,共130行) |
|
return hash; // 20字节 |
|
} |
4. SHT30 温湿度传感器 (Drivers/Sht30Sensor.cs)
纯I2C通信实现,不依赖外部传感器库。
Drivers/Sht30Sensor.cs - 核心读取
public class Sht30Sensor : IDisposable |
|
{ |
|
private I2cDevice _i2cDevice; |
|
private const byte CMD_MEASURE_HIGH_REP = 0x2C; // 单次测量(高重复性) |
|
private const byte CMD_MEASURE_HIGH_REP_2 = 0x06; |
|
public Sht30Sensor() |
|
{ |
|
// 配置I2C引脚:SDA=GPIO17, SCL=GPIO18 |
|
Configuration.SetPinFunction(17, DeviceFunction.I2C1_DATA); |
|
Configuration.SetPinFunction(18, DeviceFunction.I2C1_CLOCK); |
|
var settings = new I2cConnectionSettings(1, 0x44); // BusId=1, 地址0x44 |
|
_i2cDevice = I2cDevice.Create(settings); |
|
} |
|
public Sht30Data ReadMeasurement() |
|
{ |
|
// 1. 发送测量命令 |
|
_i2cDevice.Write(new byte[] { 0x2C, 0x06 }); |
|
// 2. 等待测量完成(高重复性≈15ms) |
|
Thread.Sleep(20); |
|
// 3. 读取6字节:[温度高, 温度低, CRC, 湿度高, 湿度低, CRC] |
|
byte[] buf = new byte[6]; |
|
_i2cDevice.Read(buf); |
|
// 4. 计算公式 |
|
int rawT = (buf[0] << 8) | buf[1]; |
|
int rawH = (buf[3] << 8) | buf[4]; |
|
double temperature = -45.0 + (175.0 * rawT / 65535.0); |
|
double humidity = 100.0 * rawH / 65535.0; |
|
// 5. CRC-8校验(多项式0x31) |
|
CheckCRC(buf[0], buf[1], buf[2]); |
|
CheckCRC(buf[3], buf[4], buf[5]); |
|
return new Sht30Data { Temperature = temperature, Humidity = humidity }; |
|
} |
|
// CRC-8校验 (x^8 + x^5 + x^4 + 1) |
|
private bool CheckCRC(byte d1, byte d2, byte crc) |
|
{ |
|
byte val = 0xFF; |
|
val ^= d1; |
|
for (int i = 0; i < 8; i++) |
|
val = (byte)((val & 0x80) != 0 ? (val << 1) ^ 0x31 : val << 1); |
|
val ^= d2; |
|
for (int i = 0; i < 8; i++) |
|
val = (byte)((val & 0x80) != 0 ? (val << 1) ^ 0x31 : val << 1); |
|
return val == crc; |
|
} |
|
} |
温度公式:T = -45 + 175 × (raw / 65535) °C
湿度公式:RH = 100 × (raw / 65535) %
5. 数据采集与上传 (Program.cs 主循环)
Program.cs - UploadDataToCloud()
private static void UploadDataToCloud() |
|
{ |
|
if (_mqttClientManager == null || !_mqttClientManager.IsConnected) return; |
|
// 采集数据 |
|
double temperature = 0, humidity = 0; |
|
bool relayState = false; |
|
if (_sht30Sensor != null) |
|
{ |
|
var data = _sht30Sensor.ReadMeasurement(); |
|
if (data != null) |
|
{ |
|
// 四舍五入保留一位小数 |
|
temperature = (int)(data.Temperature * 10 + 0.5) / 10.0; |
|
humidity = (int)(data.Humidity * 10 + 0.5) / 10.0; |
|
} |
|
} |
|
if (_relayDriver != null) |
|
relayState = _relayDriver.GetState(0); |
|
// 构建YFLink属性(属性ID需与云端物模型一致) |
|
var properties = new Hashtable |
|
{ |
|
{ "H", humidity }, // 湿度 |
|
{ "T", temperature }, // 温度 |
|
{ "I1", 0 }, // 开关量输入1 |
|
{ "I2", 0 }, // 开关量输入2 |
|
{ "Q1", relayState ? 1 : 0 } // 继电器输出1 |
|
}; |
|
_mqttClientManager.PublishProperties(properties); |
|
} |
6. 数据模型 (Models/DeviceModels.cs)
namespace YeFanIoTTest.Models |
|
{ |
|
public class DeviceConfig |
|
{ |
|
public string ProjectID { get; set; } // 项目ID |
|
public string ProductID { get; set; } // 产品ID |
|
public string DeviceID { get; set; } // 设备ID |
|
public string DeviceKey { get; set; } // 设备密钥(32位) |
|
public string MqttServer { get; set; } // MQTT服务器 |
|
public int MqttPort { get; set; } // MQTT端口 |
|
} |
|
public class WifiConfig |
|
{ |
|
public string SSID { get; set; } |
|
public string Password { get; set; } |
|
} |
|
public class SensorData |
|
{ |
|
public double Temperature { get; set; } |
|
public double Humidity { get; set; } |
|
public DateTime Timestamp { get; set; } |
|
} |
|
} |
7. 枚举定义 (Enums/Enums.cs)
namespace YeFanIoTTest.Enums |
|
{ |
|
public enum DeviceState { Initializing, CheckingConfig, APConfiguring, |
|
ConnectingWifi, ConnectingCloud, NormalRunning, Error } |
|
public enum NetworkStatus { Connecting, Connected, Disconnected, Error } |
|
public enum ConfigStatus { Configuring, Success, Failed, Normal } |
|
public enum LedBlinkMode { Off, On, SlowBlink, FastBlink } |
|
public enum EventType { Info = 0, Warning = 1, Fault = 2 } |
|
public enum ServiceType { Command = 0, Parameter = 1 } |
|
} |
8. 按钮与配网交互
Program.cs - 按钮事件处理
_buttonDriver.OnButtonEvent += (sender, e) => |
|
{ |
|
if (e.EventType == ButtonEventType.ShortPress) |
|
{ |
|
// 短按:切换继电器 |
|
_relayDriver.Toggle(0); |
|
} |
|
else if (e.EventType == ButtonEventType.LongPress) |
|
{ |
|
// 长按(3秒):启动AP配网模式 |
|
// SSID: YF3300_ESP32S3 密码: yf123456 |
|
// 配网页面: http://192.168.4.1 |
|
new Thread(() => StartAPConfigMode()).Start(); |
|
} |
|
}; |
|
// 配网完成回调 |
|
_apConfigManager.OnConfigCompleted += (sender, e) => |
|
{ |
|
if (e.Success) |
|
{ |
|
_ledManager.SetNetworkStatus(NetworkStatus.Connected); |
|
InitializeNtpTime(); // 配网成功后同步时间 |
|
} |
|
}; |
项目文件结构
YeFanIoTTest/ |
|
├── Program.cs # 主入口,12步初始化 + 主循环 |
|
├── YeFanIoTTest.nfproj # nanoFramework项目文件 |
|
├── packages.config # NuGet依赖(22个包) |
|
│ |
|
├── Hardware/ |
|
│ └── YF3300_ESP32S3.cs # 硬件引脚映射 + 系统配置常量 |
|
│ |
|
├── Drivers/ # 硬件驱动层 |
|
│ ├── Sht30Sensor.cs # SHT30温湿度传感器(I2C + CRC-8校验) |
|
│ ├── ButtonDriver.cs # BOOT按钮(短按/长按检测) |
|
│ ├── DigitalInputDriver.cs # 2路开关量输入(回调模式) |
|
│ ├── RelayDriver.cs # 1路继电器输出 |
|
│ ├── LedManager.cs # 双色LED状态指示 |
|
│ └── SerialPortManager.cs # [预留] 串口管理器 |
|
│ |
|
├── Managers/ # 业务逻辑层 |
|
│ ├── MqttClientManager.cs # ★ YFLink协议MQTT通信(含HMAC-SHA1自实现) |
|
│ ├── WifiManager.cs # WiFi STA/AP模式管理 |
|
│ ├── APConfigManager.cs # AP配网流程控制 |
|
│ ├── WebServer.cs # 配网Web页面服务 |
|
│ ├── NtpTimeManager.cs # NTP时间同步(5个服务器) |
|
│ ├── ConfigurationManager.cs # WiFi凭证持久化 |
|
│ ├── CloudCommunicationManager.cs # [预留] 云端通信管理器 |
|
│ └── DataCollectorManager.cs # [预留] 数据采集管理器 |
|
│ |
|
├── Models/ # 数据模型层 |
|
│ ├── YFLinkModels.cs # YFLink协议请求/响应模型 |
|
│ └── DeviceModels.cs # 设备配置/传感器数据模型 |
|
│ |
|
├── Enums/ |
|
│ └── Enums.cs # 6个枚举定义 |
|
│ |
|
├── Core/ |
|
│ └── DeviceManager.cs # [预留] 设备管理器 |
|
│ |
|
└── Properties/ |
|
└── AssemblyInfo.cs # 程序集元数据 |
全部代码
Program.cs
using System; |
|
using System.Device.Gpio; |
|
using System.Threading; |
|
using Microsoft.Extensions.Logging; |
|
using nanoFramework.Logging; |
|
using nanoFramework.Logging.Debug; |
|
using YeFanIoTTest.Drivers; |
|
using YeFanIoTTest.Enums; |
|
using YeFanIoTTest.Managers; |
|
using YeFanIoTTest.Models; |
|
namespace YeFanIoTTest |
|
{ |
|
public class Program |
|
{ |
|
private static LedManager _ledManager; |
|
private static GpioController _gpioController; |
|
private static ButtonDriver _buttonDriver; |
|
private static WifiManager _wifiManager; |
|
private static APConfigManager _apConfigManager; |
|
private static RelayDriver _relayDriver; |
|
private static DigitalInputDriver _digitalInputDriver; |
|
private static Sht30Sensor _sht30Sensor; |
|
private static NtpTimeManager _ntpTimeManager; |
|
private static ConfigurationManager _configurationManager; |
|
private static MqttClientManager _mqttClientManager; |
|
public static void Main() |
|
{ |
|
Console.WriteLine("========================================"); |
|
Console.WriteLine(" YF3300-ESP32S3 - Iteration 4 Test"); |
|
Console.WriteLine(" NTP Time Sync + Cloud Communication"); |
|
Console.WriteLine("========================================"); |
|
Console.WriteLine("\n[Step 1] Initializing Logger..."); |
|
try |
|
{ |
|
var factory = new DebugLoggerFactory(); |
|
if (factory != null) |
|
{ |
|
LogDispatcher.LoggerFactory = factory; |
|
Console.WriteLine("[Step 1] Logger - PASS"); |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[Step 1] Logger - FAIL: {ex.Message}"); |
|
} |
|
Thread.Sleep(500); |
|
Console.WriteLine("\n[Step 2] Initializing GPIO..."); |
|
try |
|
{ |
|
_gpioController = new GpioController(); |
|
Console.WriteLine("[Step 2] GPIO Controller - PASS"); |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[Step 2] GPIO - FAIL: {ex.Message}"); |
|
Thread.Sleep(Timeout.Infinite); |
|
} |
|
Thread.Sleep(500); |
|
Console.WriteLine("\n[Step 3] Initializing LED..."); |
|
try |
|
{ |
|
_ledManager = new LedManager(_gpioController); |
|
_ledManager.SetNetworkStatus(NetworkStatus.Connecting); |
|
_ledManager.SetConfigStatus(ConfigStatus.Normal); // 绿色LED默认熄灭(正常运行) |
|
Console.WriteLine("[Step 3] LED Manager - PASS"); |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[Step 3] LED - FAIL: {ex.Message}"); |
|
} |
|
Thread.Sleep(500); |
|
Console.WriteLine("\n[Step 4] Initializing Relay..."); |
|
try |
|
{ |
|
_relayDriver = new RelayDriver(_gpioController); |
|
Console.WriteLine("[Step 4] Relay Driver - PASS"); |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[Step 4] Relay - FAIL: {ex.Message}"); |
|
} |
|
Thread.Sleep(500); |
|
Console.WriteLine("\n[Step 5] Initializing Digital Input..."); |
|
try |
|
{ |
|
// 使用回调委托,实时响应数字输入变化 |
|
_digitalInputDriver = new DigitalInputDriver(_gpioController, OnDigitalInputChanged); |
|
Console.WriteLine("[Step 5] Digital Input Driver - PASS"); |
|
Console.WriteLine("[Step 5] Callback mode enabled (real-time response)"); |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[Step 5] Digital Input - FAIL: {ex.Message}"); |
|
} |
|
Thread.Sleep(500); |
|
Console.WriteLine("\n[Step 6] Initializing SHT30 Sensor..."); |
|
try |
|
{ |
|
_sht30Sensor = new Sht30Sensor(); |
|
Console.WriteLine("[Step 6] SHT30 Sensor - PASS"); |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[Step 6] SHT30 - FAIL: {ex.Message}"); |
|
} |
|
Thread.Sleep(500); |
|
Console.WriteLine("\n[Step 7] Initializing Button..."); |
|
try |
|
{ |
|
_buttonDriver = new ButtonDriver( |
|
_gpioController, |
|
YFSoft.Hardware.YF3300_ESP32S3.Mainboard.Pins.BOOT, |
|
debounceTime: 20, |
|
longPressTime: 3000 |
|
); |
|
Console.WriteLine("[Step 7] Button Driver - PASS"); |
|
_buttonDriver.OnButtonEvent += (sender, e) => |
|
{ |
|
Console.WriteLine($"[Button] Event: {e.EventType}, Pin: {e.PinNumber}"); |
|
if (e.EventType == ButtonEventType.ShortPress) |
|
{ |
|
if (_relayDriver != null) |
|
{ |
|
_relayDriver.Toggle(0); |
|
} |
|
Console.WriteLine("[Button] Toggled Relay 1"); |
|
} |
|
else if (e.EventType == ButtonEventType.LongPress) |
|
{ |
|
Console.WriteLine("[Button] Long press detected - Starting AP config mode..."); |
|
Thread apThread = new Thread(() => |
|
{ |
|
StartAPConfigMode(); |
|
}); |
|
apThread.Start(); |
|
} |
|
}; |
|
Console.WriteLine("[Step 7] Event Handler Registered"); |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[Step 7] Button - FAIL: {ex.Message}"); |
|
} |
|
Thread.Sleep(500); |
|
Console.WriteLine("\n[Step 8] Initializing Configuration Manager..."); |
|
try |
|
{ |
|
_configurationManager = new ConfigurationManager(); |
|
Console.WriteLine("[Step 8] Configuration Manager - PASS"); |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[Step 8] Configuration Manager - FAIL: {ex.Message}"); |
|
} |
|
Thread.Sleep(500); |
|
Console.WriteLine("\n[Step 9] Initializing WiFi Manager..."); |
|
try |
|
{ |
|
_wifiManager = new WifiManager(); |
|
Console.WriteLine("[Step 9] WiFi Manager - PASS"); |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[Step 9] WiFi Manager - FAIL: {ex.Message}"); |
|
} |
|
Thread.Sleep(500); |
|
Console.WriteLine("\n[Step 10] Checking WiFi Configuration..."); |
|
bool hasWifiConfig = false; |
|
try |
|
{ |
|
hasWifiConfig = _configurationManager.HasWifiConfig(); |
|
if (hasWifiConfig) |
|
{ |
|
Console.WriteLine("[Step 10] WiFi configuration found"); |
|
// 加载WiFi配置 |
|
WifiConfig wifiConfig; |
|
if (_configurationManager.LoadWifiConfig(out wifiConfig)) |
|
{ |
|
Console.WriteLine($"[Step 10] SSID: {wifiConfig.SSID}"); |
|
// 连接WiFi |
|
Console.WriteLine("[Step 10] Connecting to WiFi..."); |
|
bool connected = _wifiManager.ConnectSTA(wifiConfig.SSID, wifiConfig.Password); |
|
if (connected) |
|
{ |
|
Console.WriteLine("[Step 10] WiFi connected successfully"); |
|
_ledManager.SetNetworkStatus(NetworkStatus.Connected); |
|
// 初始化NTP并同步时间 |
|
InitializeNtpTime(); |
|
} |
|
else |
|
{ |
|
Console.WriteLine("[Step 10] WiFi connection failed"); |
|
_ledManager.SetNetworkStatus(NetworkStatus.Disconnected); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
Console.WriteLine("[Step 10] No WiFi configuration found"); |
|
Console.WriteLine("[Step 10] Long press BOOT button to start AP config mode"); |
|
_ledManager.SetNetworkStatus(NetworkStatus.Disconnected); |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[Step 10] WiFi Check - FAIL: {ex.Message}"); |
|
} |
|
Thread.Sleep(500); |
|
Console.WriteLine("\n[Step 11] Initializing AP Config Manager..."); |
|
try |
|
{ |
|
_apConfigManager = new APConfigManager(_wifiManager); |
|
// 设置WebServerController的APConfigManager实例引用 |
|
WebServerController.SetAPConfigManager(_apConfigManager); |
|
Console.WriteLine("[Step 11] AP Config Manager - PASS"); |
|
_apConfigManager.OnConfigCompleted += (sender, e) => |
|
{ |
|
Console.WriteLine($"[AP Config] Result: {(e.Success ? "SUCCESS" : "FAILED")}"); |
|
Console.WriteLine($"[AP Config] SSID: {e.SSID}"); |
|
Console.WriteLine($"[AP Config] Message: {e.Message}"); |
|
// 检查是否网络可达 |
|
bool networkReachable = e.Message.Contains("网络可达"); |
|
if (e.Success && networkReachable) |
|
{ |
|
// ========== 网络可达:配网真正成功 ========== |
|
Console.WriteLine("[AP Config] Network is reachable - Configuration successful!"); |
|
// ========== 暂时注释:不保存WiFi配置 ========== |
|
// if (_configurationManager != null) |
|
// { |
|
// var wifiConfig = new WifiConfig { SSID = e.SSID, Password = e.Password }; |
|
// _configurationManager.SaveWifiConfig(wifiConfig); |
|
// Console.WriteLine("[AP Config] WiFi configuration saved"); |
|
// } |
|
if (_ledManager != null) |
|
{ |
|
_ledManager.SetNetworkStatus(NetworkStatus.Connected); |
|
} |
|
// 配网成功后,初始化NTP并同步时间 |
|
InitializeNtpTime(); |
|
} |
|
else if (e.Success && !networkReachable) |
|
{ |
|
// ========== 网络不可达:配网失败 ========== |
|
Console.WriteLine("[AP Config] Network is NOT reachable - Configuration failed!"); |
|
Console.WriteLine("[AP Config] Please check your router internet connection"); |
|
if (_ledManager != null) |
|
{ |
|
_ledManager.SetNetworkStatus(NetworkStatus.Disconnected); |
|
} |
|
} |
|
else |
|
{ |
|
// ========== WiFi连接失败 ========== |
|
Console.WriteLine("[AP Config] WiFi connection failed"); |
|
if (_ledManager != null) |
|
{ |
|
_ledManager.SetNetworkStatus(NetworkStatus.Disconnected); |
|
} |
|
} |
|
}; |
|
Console.WriteLine("[Step 11] Event Handler Registered"); |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[Step 11] AP Config Manager - FAIL: {ex.Message}"); |
|
} |
|
Console.WriteLine("\n========================================"); |
|
Console.WriteLine(" Iteration 4 Test Complete!"); |
|
Console.WriteLine("========================================"); |
|
Console.WriteLine("\nTest Instructions:"); |
|
Console.WriteLine("1. Short press BOOT button to toggle relay"); |
|
Console.WriteLine("2. Long press BOOT button to start AP config mode"); |
|
Console.WriteLine("3. Digital inputs use real-time callback mode"); |
|
Console.WriteLine("4. Monitor temperature, humidity and time every 5 seconds"); |
|
Console.WriteLine("5. Upload data to cloud every 30 seconds"); |
|
Console.WriteLine("\nPress CTRL+C to exit\n"); |
|
// ========== 步骤12:连接MQTT服务器 ========== |
|
Console.WriteLine("\n[Step 12] Connecting to MQTT Server..."); |
|
try |
|
{ |
|
_mqttClientManager = new MqttClientManager(); |
|
bool mqttConnected = _mqttClientManager.Connect(); |
|
if (mqttConnected) |
|
{ |
|
Console.WriteLine("[Step 12] MQTT Connected successfully!"); |
|
} |
|
else |
|
{ |
|
Console.WriteLine("[Step 12] MQTT Connection failed!"); |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[Step 12] MQTT Error: {ex.Message}"); |
|
} |
|
Thread.Sleep(500); |
|
if (_ledManager != null) |
|
{ |
|
_ledManager.SetNetworkStatus(NetworkStatus.Connected); |
|
} |
|
int counter = 0; |
|
while (true) |
|
{ |
|
try |
|
{ |
|
counter++; |
|
Console.WriteLine($"\n--- Reading #{counter} ---"); |
|
// 显示时间 |
|
if (_ntpTimeManager != null) |
|
{ |
|
try |
|
{ |
|
var localTime = _ntpTimeManager.GetLocalTime(); |
|
Console.WriteLine($"Time: {localTime:yyyy-MM-dd HH:mm:ss}"); |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"Time: Error - {ex.Message}"); |
|
} |
|
} |
|
else |
|
{ |
|
Console.WriteLine("Time: NTP not initialized"); |
|
} |
|
// 读取温湿度 |
|
if (_sht30Sensor != null) |
|
{ |
|
try |
|
{ |
|
var sht30Data = _sht30Sensor.ReadMeasurement(); |
|
if (sht30Data != null) |
|
{ |
|
Console.WriteLine($"Temperature: {sht30Data.Temperature:F1}°C, Humidity: {sht30Data.Humidity:F1}%"); |
|
} |
|
else |
|
{ |
|
Console.WriteLine("Temperature: N/A, Humidity: N/A"); |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"Temperature: Error - {ex.Message}"); |
|
} |
|
} |
|
else |
|
{ |
|
Console.WriteLine("Temperature: Sensor not initialized"); |
|
} |
|
// 读取数字输入状态(轮询模式,作为备份) |
|
if (_digitalInputDriver != null) |
|
{ |
|
try |
|
{ |
|
for (int i = 0; i < 2; i++) |
|
{ |
|
var state = _digitalInputDriver.ReadState(i); |
|
Console.WriteLine($"Digital Input {i + 1}: {(state ? "Triggered" : "Not triggered")}"); |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"Digital Input: Error - {ex.Message}"); |
|
} |
|
} |
|
else |
|
{ |
|
Console.WriteLine("Digital Input: Driver not initialized"); |
|
} |
|
// 读取继电器状态 |
|
if (_relayDriver != null) |
|
{ |
|
try |
|
{ |
|
var relayState = _relayDriver.GetState(0); |
|
Console.WriteLine($"Relay 1: {(relayState ? "ON" : "OFF")}"); |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"Relay: Error - {ex.Message}"); |
|
} |
|
} |
|
else |
|
{ |
|
Console.WriteLine("Relay: Driver not initialized"); |
|
} |
|
Thread.Sleep(5000); |
|
// ========== 上传数据到云端(每30秒) ========== |
|
if (counter % 6 == 0) // 每6次读取(约30秒)上传一次 |
|
{ |
|
UploadDataToCloud(); |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"Error in monitoring loop: {ex.Message}"); |
|
Thread.Sleep(1000); |
|
} |
|
} |
|
} |
|
// 初始化NTP并同步时间 |
|
private static void InitializeNtpTime() |
|
{ |
|
try |
|
{ |
|
Console.WriteLine("\n[NTP] Initializing NTP Time Manager..."); |
|
_ntpTimeManager = new NtpTimeManager(); |
|
Console.WriteLine("[NTP] Starting NTP client..."); |
|
bool ntpInitSuccess = _ntpTimeManager.Initialize(); |
|
if (ntpInitSuccess) |
|
{ |
|
Console.WriteLine("[NTP] NTP Client started"); |
|
Console.WriteLine("[NTP] Syncing time..."); |
|
Thread.Sleep(2000); // 等待2秒让NTP同步 |
|
bool syncSuccess = _ntpTimeManager.SyncNow(); |
|
if (syncSuccess) |
|
{ |
|
var utcTime = _ntpTimeManager.GetCurrentTime(); |
|
var localTime = _ntpTimeManager.GetLocalTime(); |
|
Console.WriteLine($"[NTP] UTC Time: {utcTime:yyyy-MM-dd HH:mm:ss}"); |
|
Console.WriteLine($"[NTP] Local Time: {localTime:yyyy-MM-dd HH:mm:ss}"); |
|
Console.WriteLine("[NTP] Time sync successful"); |
|
} |
|
else |
|
{ |
|
Console.WriteLine("[NTP] Time sync failed"); |
|
} |
|
} |
|
else |
|
{ |
|
Console.WriteLine("[NTP] NTP Client start failed"); |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[NTP] Error: {ex.Message}"); |
|
} |
|
} |
|
// 上传数据到云端 |
|
private static void UploadDataToCloud() |
|
{ |
|
if (_mqttClientManager == null || !_mqttClientManager.IsConnected) |
|
{ |
|
Console.WriteLine("[Cloud] MQTT not connected, skipping data upload"); |
|
return; |
|
} |
|
try |
|
{ |
|
// 收集数据 |
|
double temperature = 0; |
|
double humidity = 0; |
|
bool relayState = false; |
|
// 读取温湿度(保留一位小数) |
|
if (_sht30Sensor != null) |
|
{ |
|
var sht30Data = _sht30Sensor.ReadMeasurement(); |
|
if (sht30Data != null) |
|
{ |
|
// 使用整数运算实现四舍五入 |
|
temperature = (int)(sht30Data.Temperature * 10 + 0.5) / 10.0; |
|
humidity = (int)(sht30Data.Humidity * 10 + 0.5) / 10.0; |
|
} |
|
} |
|
// 读取继电器状态 |
|
if (_relayDriver != null) |
|
{ |
|
relayState = _relayDriver.GetState(0); |
|
} |
|
// 构建属性数据(使用YFLink协议规定的属性ID) |
|
// H - 湿度(百分比) |
|
// T - 温度(摄氏度) |
|
// I1 - 开关量输入1 |
|
// I2 - 开关量输入2 |
|
// Q1 - 继电器输出1 |
|
var properties = new System.Collections.Hashtable |
|
{ |
|
{ "H", humidity }, // 湿度 |
|
{ "T", temperature }, // 温度 |
|
{ "I1", 0 }, // 开关量输入1(待实现) |
|
{ "I2", 0 }, // 开关量输入2(待实现) |
|
{ "Q1", relayState ? 1 : 0 } // 继电器输出1 |
|
}; |
|
// 上传属性 |
|
bool uploadSuccess = _mqttClientManager.PublishProperties(properties); |
|
if (uploadSuccess) |
|
{ |
|
Console.WriteLine($"[Cloud] Data uploaded: H={humidity:F1}%, T={temperature:F1}°C, I1=0, I2=0, Q1={(relayState ? 1 : 0)}"); |
|
} |
|
else |
|
{ |
|
Console.WriteLine("[Cloud] Data upload failed"); |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[Cloud] Upload error: {ex.Message}"); |
|
} |
|
} |
|
// 数字输入状态变化回调 |
|
// 【重要】此方法在GPIO中断上下文中执行,必须遵循BUG1.md的规则 |
|
// channel: 通道号(从0开始) |
|
// isTriggered: 是否触发(true=低电平触发,false=高电平未触发) |
|
// pinValue: 引脚电平值(0=低电平,1=高电平) |
|
private static void OnDigitalInputChanged(int channel, bool isTriggered, int pinValue) |
|
{ |
|
// 在中断上下文中,只能做最简单的操作 |
|
// 使用Console.WriteLine输出,不创建对象 |
|
Console.WriteLine($"[Digital Input] Channel {channel + 1}: {(isTriggered ? "Triggered" : "Not triggered")} (Pin: {pinValue})"); |
|
} |
|
private static void StartAPConfigMode() |
|
{ |
|
try |
|
{ |
|
Console.WriteLine("\n[AP Config] Starting AP configuration mode..."); |
|
if (_ledManager != null) |
|
{ |
|
_ledManager.SetNetworkStatus(NetworkStatus.Connecting); |
|
} |
|
Thread.Sleep(100); |
|
bool success = _apConfigManager.StartAPConfig(); |
|
if (success) |
|
{ |
|
Console.WriteLine("[AP Config] AP mode started successfully"); |
|
Console.WriteLine("[AP Config] SSID: YF3300_ESP32S3"); |
|
Console.WriteLine("[AP Config] Password: yf123456"); |
|
Console.WriteLine("[AP Config] IP: 192.168.4.1"); |
|
} |
|
else |
|
{ |
|
Console.WriteLine("[AP Config] Failed to start AP mode"); |
|
if (_ledManager != null) |
|
{ |
|
_ledManager.SetNetworkStatus(NetworkStatus.Disconnected); |
|
} |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
Console.WriteLine($"[AP Config] Error: {ex.Message}"); |
|
Console.WriteLine($"[AP Config] Exception Type: {ex.GetType().Name}"); |
|
if (_ledManager != null) |
|
{ |
|
_ledManager.SetNetworkStatus(NetworkStatus.Disconnected); |
|
} |
|
} |
|
} |
|
} |
|
} |
Hardware/YF3300_ESP32S3.cs
using System; |
|
namespace YFSoft.Hardware.YF3300_ESP32S3 |
|
{ |
|
public static class CPU |
|
{ |
|
public static class Pins |
|
{ |
|
// GPIO 0-47 |
|
public const int GPIO0 = 0; |
|
public const int GPIO1 = 1; |
|
public const int GPIO2 = 2; |
|
public const int GPIO3 = 3; |
|
public const int GPIO4 = 4; |
|
public const int GPIO5 = 5; |
|
public const int GPIO6 = 6; |
|
public const int GPIO7 = 7; |
|
public const int GPIO8 = 8; |
|
public const int GPIO9 = 9; |
|
public const int GPIO10 = 10; |
|
public const int GPIO11 = 11; |
|
public const int GPIO12 = 12; |
|
public const int GPIO13 = 13; |
|
public const int GPIO14 = 14; |
|
public const int GPIO15 = 15; |
|
public const int GPIO16 = 16; |
|
public const int GPIO17 = 17; |
|
public const int GPIO18 = 18; |
|
public const int GPIO19 = 19; |
|
public const int GPIO20 = 20; |
|
public const int GPIO21 = 21; |
|
public const int GPIO22 = 22; |
|
public const int GPIO23 = 23; |
|
public const int GPIO24 = 24; |
|
public const int GPIO25 = 25; |
|
public const int GPIO26 = 26; |
|
public const int GPIO27 = 27; |
|
public const int GPIO28 = 28; |
|
public const int GPIO29 = 29; |
|
public const int GPIO30 = 30; |
|
public const int GPIO31 = 31; |
|
public const int GPIO32 = 32; |
|
public const int GPIO33 = 33; |
|
public const int GPIO34 = 34; |
|
public const int GPIO35 = 35; |
|
public const int GPIO36 = 36; |
|
public const int GPIO37 = 37; |
|
public const int GPIO38 = 38; |
|
public const int GPIO39 = 39; |
|
public const int GPIO40 = 40; |
|
public const int GPIO41 = 41; |
|
public const int GPIO42 = 42; |
|
public const int GPIO43 = 43; |
|
public const int GPIO44 = 44; |
|
public const int GPIO45 = 45; |
|
public const int GPIO46 = 46; |
|
public const int GPIO47 = 47; |
|
public const int GPIO48 = 48; |
|
} |
|
} |
|
public static class Mainboard |
|
{ |
|
// 主板引脚定义 |
|
public static class Pins |
|
{ |
|
// LED 指示灯(根据实际硬件连接) |
|
public const int YellowLED = CPU.Pins.GPIO40; // 黄色LED - 网络状态指示 |
|
public const int GreenLED = CPU.Pins.GPIO39; // 绿色LED - 配网状态指示 |
|
// 兼容旧命名 |
|
public const int CommLED = YellowLED; // 通信指示灯(黄色) |
|
public const int UserLED = GreenLED; // 用户指示灯(绿色) |
|
// 按钮 |
|
public const int BOOT = CPU.Pins.GPIO0; |
|
// 开关量输入 |
|
public const int I1 = CPU.Pins.GPIO21; // 输入1 |
|
public const int I2 = CPU.Pins.GPIO47; // 输入2 |
|
// 继电器输出 |
|
public const int Q1 = CPU.Pins.GPIO48; // 继电器1 |
|
} |
|
// RS485 串口定义 |
|
public static class RS485 |
|
{ |
|
public const string PortName = "COM1"; |
|
public const int DefaultBaudRate = 9600; |
|
public const int TxPin = CPU.Pins.GPIO9; // UART1 TX (电路图: TX1=IO9) |
|
public const int RxPin = CPU.Pins.GPIO10; // UART1 RX (电路图: RX1=IO10) |
|
} |
|
// RS232 串口定义 |
|
public static class RS232 |
|
{ |
|
public const string PortName = "COM2"; |
|
public const int DefaultBaudRate = 9600; |
|
public const int TxPin = CPU.Pins.GPIO11; // UART2 TX (电路图: TX2=IO11) |
|
public const int RxPin = CPU.Pins.GPIO12; // UART2 RX (电路图: RX2=IO12) |
|
} |
|
// I2C 总线定义 |
|
public static class I2C |
|
{ |
|
public const int BusId = 1; |
|
public const int SdaPin = CPU.Pins.GPIO17; |
|
public const int SclPin = CPU.Pins.GPIO18; |
|
public const int DefaultSpeed = 100000; // 100kHz |
|
} |
|
// 开关量输入通道 |
|
public static class DigitalInputs |
|
{ |
|
public const int Count = 2; |
|
public static readonly int[] Channels = { Mainboard.Pins.I1, Mainboard.Pins.I2 }; |
|
} |
|
// 继电器输出通道 |
|
public static class Relays |
|
{ |
|
public const int Count = 1; |
|
public static readonly int[] Channels = { Mainboard.Pins.Q1 }; |
|
} |
|
// LED 闪烁时间定义(毫秒) |
|
public static class LEDTiming |
|
{ |
|
// 黄色LED - 网络状态指示 |
|
public const int NetworkConnecting_On = 0; // 常亮(正在连接) |
|
public const int NetworkConnecting_Off = int.MaxValue; |
|
public const int NetworkNormal_On = 500; // 慢闪(正常) |
|
public const int NetworkNormal_Off = 1500; |
|
public const int NetworkError_On = 200; // 快闪(异常) |
|
public const int NetworkError_Off = 200; |
|
// 绿色LED - 配网状态指示 |
|
public const int ConfigAP_On = 0; // 常亮(配网中) |
|
public const int ConfigAP_Off = int.MaxValue; |
|
public const int ConfigSuccess_On = 500; // 慢闪(配网成功) |
|
public const int ConfigSuccess_Off = 1500; |
|
public const int ConfigFailed_On = 200; // 快闪(配网失败) |
|
public const int ConfigFailed_Off = 200; |
|
public const int ConfigNormal_On = 0; // 熄灭(正常运行) |
|
public const int ConfigNormal_Off = 0; |
|
} |
|
} |
|
// 设备信息定义 |
|
public static class DeviceInfo |
|
{ |
|
public const string DeviceName = "YF3300-ESP32S3"; // 设备名称 |
|
public const string Manufacturer = "YFSoft"; // 制造商 |
|
public const string HardwareVersion = "1.0.0"; // 硬件版本 |
|
public const string FirmwareVersion = "1.0.0"; // 固件版本 |
|
public const string Model = "YF3300-ESP32S3"; // 设备型号 |
|
} |
|
// 系统配置常量 |
|
public static class SystemConfig |
|
{ |
|
// WiFi 配置 |
|
public const int WiFiConnectTimeout = 15000; // WiFi连接超时(毫秒) |
|
public const int WiFiReconnectInterval = 5000; // WiFi重连间隔(毫秒) |
|
// MQTT 配置 |
|
public const string DefaultMqttServer = "mqtt.yfiot.com"; // 默认MQTT服务器 |
|
public const int DefaultMqttPort = 1883; // 默认MQTT端口 |
|
public const int MqttKeepAliveInterval = 60; // MQTT心跳间隔(秒) |
|
public const int MqttReconnectInterval = 5000; // MQTT重连间隔(毫秒) |
|
// AP 配网配置 |
|
public const string APSSID = "YF3300_ESP32S3"; // AP热点名称 |
|
public const string APPassword = "yf123456"; // AP热点密码 |
|
public const string APIP = "192.168.4.1"; // AP网关IP |
|
public const int APConfigTimeout = 600000; // 配网超时(10分钟) |
|
// 数据采集配置 |
|
public const int SensorReadInterval = 30000; // 传感器读取间隔(毫秒) |
|
public const int DataUploadInterval = 30000; // 数据上传间隔(毫秒) |
|
// 看门狗配置 |
|
public const int WatchdogTimeout = 30000; // 看门狗超时(毫秒) |
|
// NTP 配置 |
|
public const string DefaultNtpServer = "ntp.aliyun.com"; // 默认NTP服务器 |
|
public const int NtpSyncInterval = 3600000; // NTP同步间隔(1小时) |
|
// 按钮配置 |
|
public const int ButtonLongPressDuration = 5000; // 长按时间(毫秒) |
|
public const int ButtonDebounceTime = 50; // 按钮防抖时间(毫秒) |
|
} |
|
} |
Models/YFLinkModels.cs
using System; |
|
using System.Collections; |
|
namespace YeFanIoTTest.Models |
|
{ |
|
// YFLink协议基础请求模型 |
|
public class YFLinkRequest |
|
{ |
|
public int id { get; set; } // 消息ID(32位整数) |
|
public string ver { get; set; } = "1.3.0"; // 协议版本 |
|
public long timestamp { get; set; } // 时间戳(1970年1月1日以来的毫秒数) |
|
} |
|
// YFLink协议基础响应模型 |
|
public class YFLinkResponse |
|
{ |
|
public int id { get; set; } // 消息ID(与请求ID对应) |
|
public int code { get; set; } // 返回结果编码(200表示成功) |
|
public string message { get; set; } // 返回结果描述 |
|
} |
|
// 属性上传请求模型 |
|
public class PropertyPostRequest : YFLinkRequest |
|
{ |
|
public Hashtable parameters { get; set; } // 属性键值对集合 |
|
} |
|
// 属性上传响应模型 |
|
public class PropertyPostResponse : YFLinkResponse |
|
{ |
|
public ArrayList data { get; set; } // 验证不通过的属性标识列表 |
|
} |
|
// 事件上传请求模型 |
|
public class EventPostRequest : YFLinkRequest |
|
{ |
|
public ArrayList parameters { get; set; } // 事件数据列表 |
|
} |
|
// 事件数据模型 |
|
public class EventData |
|
{ |
|
public int type { get; set; } // 事件类型(0-信息,1-告警,2-故障) |
|
public int code { get; set; } // 事件编码(32位整数) |
|
public string content { get; set; } // 事件内容(不超过1024字节) |
|
public long time { get; set; } // 事件时间戳 |
|
} |
|
// 服务下发请求模型 |
|
public class ServiceSendRequest : YFLinkRequest |
|
{ |
|
public int serviceType { get; set; } // 服务类型(0-命令,1-参数) |
|
public ServiceParams parameters { get; set; } // 服务参数 |
|
} |
|
// 服务参数模型 |
|
public class ServiceParams |
|
{ |
|
public string command { get; set; } // 服务命令 |
|
public string parameter { get; set; } // 服务参数 |
|
} |
|
// 服务响应模型 |
|
public class ServiceSendResponse : YFLinkRequest |
|
{ |
|
public ServiceResultParams parameters { get; set; } // 服务响应参数 |
|
} |
|
// 服务响应参数模型 |
|
public class ServiceResultParams |
|
{ |
|
public int code { get; set; } // 服务响应标识符 |
|
public string content { get; set; } // 服务响应内容 |
|
} |
|
// NTP校时请求模型 |
|
public class NtpRequest : YFLinkRequest |
|
{ |
|
public NtpParams parameters { get; set; } // NTP参数 |
|
} |
|
// NTP参数模型 |
|
public class NtpParams |
|
{ |
|
public long deviceSendTime { get; set; } // 设备发送请求的时间 |
|
} |
|
// NTP校时响应模型 |
|
public class NtpResponse : YFLinkResponse |
|
{ |
|
public NtpResponseParams parameters { get; set; } // NTP响应参数 |
|
} |
|
// NTP响应参数模型 |
|
public class NtpResponseParams |
|
{ |
|
public long deviceSendTime { get; set; } // 设备发送请求的时间 |
|
public long serverRecvTime { get; set; } // 服务器接收到该请求的时间 |
|
public long serverSendTime { get; set; } // 服务器发起发送该响应的时间 |
|
} |
|
} |
Models/DeviceModels.cs
using System; |
|
namespace YeFanIoTTest.Models |
|
{ |
|
// 设备配置模型 - 包含YFLink协议四元组及MQTT服务器配置 |
|
public class DeviceConfig |
|
{ |
|
public string ProjectID { get; set; } // 项目ID |
|
public string ProductID { get; set; } // 产品ID |
|
public string DeviceID { get; set; } // 设备ID |
|
public string DeviceKey { get; set; } // 设备密钥(32位随机字符) |
|
public string MqttServer { get; set; } // MQTT服务器地址 |
|
public int MqttPort { get; set; } // MQTT服务器端口 |
|
// 验证设备配置是否有效 |
|
public bool IsValid() |
|
{ |
|
return !string.IsNullOrEmpty(ProjectID) && |
|
!string.IsNullOrEmpty(ProductID) && |
|
!string.IsNullOrEmpty(DeviceID) && |
|
!string.IsNullOrEmpty(DeviceKey); |
更多推荐


所有评论(0)