Skip to content

maker-community/esp-signalr-example

Repository files navigation

ESP32 SignalR 测试示例

这是一个完整的ESP32 SignalR客户端测试示例,演示如何使用 esp-signalr 库连接到ASP.NET Core SignalR服务器。

🗂️ 文档导航

📋 功能特性

  • ✅ WiFi 连接管理
  • ✅ SignalR Hub 连接
  • ✅ 消息发送和接收
  • ✅ 多种消息处理器
  • ✅ 自动重连机制
  • ✅ 错误处理和日志
  • ✅ 定期发送测试消息
  • ✅ 模拟传感器数据上报
  • ✅ 内存使用监控

🛠 硬件要求

  • ESP32 / ESP32-S2 / ESP32-S3 / ESP32-C3 / ESP32-C6 开发板
  • USB 数据线
  • WiFi 网络环境

📦 软件要求

  • ESP-IDF >= 5.0.0
  • Python 3.6+
  • ASP.NET Core SignalR 服务器 (用于测试)

🚀 快速开始

1. 克隆项目

cd d:\github\esp-signalr-example

2. 安装 esp-signalr 库

# 创建 managed_components 目录
mkdir managed_components
cd managed_components

# 克隆 esp-signalr 库
git clone https://github.com/maker-community/esp-signalr.git verdure__esp-signalr
cd ..

3. 配置 WiFi 和 SignalR 服务器

使用 ESP-IDF 的 menuconfig 工具配置项目:

idf.py menuconfig

在菜单中导航到:

ESP SignalR Example Configuration  --->
    WiFi Configuration  --->
        WiFi SSID: 输入你的WiFi名称
        WiFi Password: 输入你的WiFi密码
    SignalR Configuration  --->
        SignalR Hub URL: 输入你的服务器地址

示例配置:

  • WiFi SSID: MyWiFi
  • WiFi Password: MyPassword123
  • SignalR Hub URL: http://192.168.1.100:5000/chatHub

配置完成后按 S 保存,然后按 Q 退出。

配置选项说明:

配置项 说明 默认值
WiFi SSID WiFi网络名称 myssid
WiFi Password WiFi密码 mypassword
Maximum retry WiFi最大重试次数 5
SignalR Hub URL SignalR服务器地址 http://192.168.1.100:5000/chatHub
Enable Auto Reconnect 启用自动重连
Reconnect Interval 重连间隔(秒) 5

注意: 配置保存在 sdkconfig 文件中,如需重新配置可随时运行 idf.py menuconfig

4. 构建和烧录

# 设置目标芯片 (根据你的开发板选择)
idf.py set-target esp32

# 构建项目
idf.py build

# 烧录到设备
idf.py flash

# 查看串口输出
idf.py monitor

或者一次性执行:

idf.py flash monitor

📡 SignalR 服务器设置

快速测试服务器 (ASP.NET Core)

创建一个简单的 SignalR 测试服务器:

1. 创建项目

dotnet new web -n SignalRTestServer
cd SignalRTestServer
dotnet add package Microsoft.AspNetCore.SignalR

2. 创建 Hub (ChatHub.cs)

using Microsoft.AspNetCore.SignalR;

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
    {
        Console.WriteLine($"Received from {user}: {message}");
        await Clients.All.SendAsync("ReceiveMessage", user, message);
    }

    public async Task UpdateSensor(string sensorId, double value)
    {
        Console.WriteLine($"Sensor {sensorId}: {value}");
        await Clients.All.SendAsync("UpdateSensorData", sensorId, value);
    }

    public override async Task OnConnectedAsync()
    {
        Console.WriteLine($"Client connected: {Context.ConnectionId}");
        await base.OnConnectedAsync();
        await Clients.Caller.SendAsync("Notification", "Welcome to SignalR!");
    }

    public override async Task OnDisconnectedAsync(Exception? exception)
    {
        Console.WriteLine($"Client disconnected: {Context.ConnectionId}");
        await base.OnDisconnectedAsync(exception);
    }
}

3. 配置服务器 (Program.cs)

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSignalR();
builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(builder =>
    {
        builder.AllowAnyOrigin()
               .AllowAnyHeader()
               .AllowAnyMethod();
    });
});

var app = builder.Build();

app.UseCors();
app.MapHub<ChatHub>("/chatHub");

// 监听所有网络接口
app.Urls.Add("http://0.0.0.0:5000");

Console.WriteLine("SignalR server running on http://0.0.0.0:5000");
Console.WriteLine("Hub endpoint: http://0.0.0.0:5000/chatHub");

app.Run();

4. 运行服务器

dotnet run

服务器将在 http://0.0.0.0:5000 上运行。

📊 示例输出

ESP32 串口输出

I (0) SIGNALR_EXAMPLE: ==============================================
I (0) SIGNALR_EXAMPLE:    ESP32 SignalR Client Test Example
I (0) SIGNALR_EXAMPLE: ==============================================

I (320) SIGNALR_EXAMPLE: ✓ NVS initialized

I (330) SIGNALR_EXAMPLE: Step 1: Initializing WiFi...
I (2450) SIGNALR_EXAMPLE: ✓ Connected to WiFi SSID: MyWiFi
I (2455) SIGNALR_EXAMPLE: Got IP address: 192.168.1.105

I (3460) SIGNALR_EXAMPLE: Step 2: Initializing SignalR...
I (3462) SIGNALR_EXAMPLE: ✓ SignalR connection object created

I (3465) SIGNALR_EXAMPLE: Step 3: Setting up message handlers...
I (3470) SIGNALR_EXAMPLE: ✓ Registered handler: ReceiveMessage
I (3475) SIGNALR_EXAMPLE: ✓ Registered handler: Notification
I (3480) SIGNALR_EXAMPLE: ✓ Registered handler: UpdateSensorData

I (3485) SIGNALR_EXAMPLE: Step 5: Starting SignalR connection...
I (4520) SIGNALR_EXAMPLE: ==============================================
I (4520) SIGNALR_EXAMPLE: ✓✓✓ Connected to SignalR Hub! ✓✓✓
I (4525) SIGNALR_EXAMPLE: ==============================================

I (4530) SIGNALR_EXAMPLE: 🔔 Notification: Welcome to SignalR!

I (14530) SIGNALR_EXAMPLE: 📤 Sending message...
I (14532) SIGNALR_EXAMPLE:    User: ESP32-Device
I (14535) SIGNALR_EXAMPLE:    Message: Test message #1 from ESP32
I (14640) SIGNALR_EXAMPLE: ✓ Message sent successfully!

I (14650) SIGNALR_EXAMPLE: ==============================================
I (14655) SIGNALR_EXAMPLE: 📩 Message received from server:
I (14660) SIGNALR_EXAMPLE:    From: ESP32-Device
I (14665) SIGNALR_EXAMPLE:    Text: Test message #1 from ESP32
I (14670) SIGNALR_EXAMPLE: ==============================================

🎯 支持的消息类型

1. ReceiveMessage - 接收聊天消息

// 服务器发送
await Clients.All.SendAsync("ReceiveMessage", "username", "message text");

// ESP32 接收
connection.on("ReceiveMessage", [](const std::vector<signalr::value>& args) {
    std::string user = args[0].as_string();
    std::string message = args[1].as_string();
    // 处理消息
});

2. UpdateSensorData - 传感器数据

// ESP32 发送
send_sensor_data("Temperature", 25.5);

// 服务器接收
public async Task UpdateSensor(string sensorId, double value)
{
    await Clients.All.SendAsync("UpdateSensorData", sensorId, value);
}

3. Notification - 通知消息

// 服务器发送
await Clients.Caller.SendAsync("Notification", "Welcome!");

// ESP32 接收
connection.on("Notification", [](const std::vector<signalr::value>& args) {
    ESP_LOGI(TAG, "Notification: %s", args[0].as_string().c_str());
});

🔧 配置选项

sdkconfig.defaults

# C++ 异常支持 (必需)
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=512

# 主任务堆栈大小
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192

# WiFi 缓冲区
CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32
CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=32

# 网络套接字
CONFIG_LWIP_MAX_SOCKETS=16

内存优化

如果遇到内存不足,可以启用 PSRAM:

CONFIG_SPIRAM=y
CONFIG_SPIRAM_USE_MALLOC=y

📈 性能指标

  • 内存使用: ~45KB RAM (典型)
  • 连接时间: 2-4 秒 (包括协商)
  • 消息延迟: 50-150ms (取决于网络)
  • 吞吐量: ~100 消息/秒 (小消息)

🐛 故障排除

问题 1: 编译错误 - C++ exceptions not enabled

解决方案:

idf.py menuconfig
# 导航到: Component config → Compiler options → Enable C++ exceptions

或确保 sdkconfig.defaults 包含:

CONFIG_COMPILER_CXX_EXCEPTIONS=y

问题 2: WiFi 连接失败

检查:

  • WiFi SSID 和密码是否正确
  • WiFi 信号强度是否足够
  • 路由器是否支持 2.4GHz (ESP32 不支持 5GHz)

问题 3: SignalR 连接失败

检查:

  • 服务器是否运行: netstat -an | findstr 5000
  • URL 是否正确 (注意 IP 地址和端口)
  • 防火墙是否允许连接
  • 服务器日志是否有错误

问题 4: 内存不足

解决方案:

# 启用 PSRAM
CONFIG_SPIRAM=y
CONFIG_SPIRAM_USE_MALLOC=y

# 增加堆栈大小
CONFIG_ESP_MAIN_TASK_STACK_SIZE=16384

问题 5: 频繁断线重连

原因:

  • 网络不稳定
  • 服务器超时设置太短
  • 消息处理耗时过长

解决方案:

  • 检查网络质量
  • 增加服务器超时时间
  • 优化消息处理逻辑

📚 相关资源

🔍 代码架构说明

ESP-SignalR 库架构

┌──────────────────────────────────────────────────────────┐
│  SignalR 核心协议 (不变)                                    │
│  - Hub 连接, 协商, 握手                                     │
│  - JSON 协议, 消息路由                                      │
└──────────────────────────────────────────────────────────┘
                          ↓ 抽象接口
┌──────────────────────────────────────────────────────────┐
│  平台适配器 (ESP32 实现)                                    │
│  - esp32_websocket_client  → esp_websocket_client        │
│  - esp32_http_client       → esp_http_client             │
│  - JSON 适配器             → cJSON                        │
│  - 调度器适配器            → FreeRTOS                     │
└──────────────────────────────────────────────────────────┘

关键组件

  1. esp32_websocket_client: WebSocket 传输层

    • 包装 ESP-IDF 的 esp_websocket_client
    • 处理 WebSocket 生命周期事件
    • 使用 FreeRTOS EventGroups 进行同步
  2. esp32_http_client: HTTP 客户端

    • 包装 ESP-IDF 的 esp_http_client
    • 用于 SignalR 协商阶段
    • 支持 GET 和 POST 请求
  3. json_adapter: JSON 序列化

    • 使用 ESP32 原生的 cJSON
    • API 兼容原始 SignalR 协议
    • 高效的内存管理
  4. signalr_default_scheduler: FreeRTOS 调度器

    • 基于 FreeRTOS 任务的线程池
    • 5 个可配置的工作线程
    • 适当的同步机制

💡 使用建议

  1. WiFi 连接: 总是在启动 SignalR 之前检查 WiFi 连接
  2. 自动重连: 在生产系统中实现自动重连
  3. 内存监控: 开发期间监控内存使用
  4. 消息大小: 保持消息负载小 (推荐 < 4KB)
  5. 错误处理: 为所有回调实现适当的错误处理
  6. 日志级别: 生产环境中降低日志级别以节省内存

📝 许可证

MIT License - 详见 LICENSE 文件

🙏 致谢

📧 支持

如有问题或建议,请:


祝你使用愉快! 🚀

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors