-
C#网络编程之IoT平台开发(Azure IoT Hub、AWS IoT Core)
《C#网络编程实战:从入门到企业级开发》
第三十四部分:IoT平台开发实战
第63章 IoT平台开发(Azure IoT Hub、AWS IoT Core)
一、我踩过的IoT平台坑:从“Azure设备孪生没生效导致设备采样错误”到“AWS规则引擎配置错了丢失3天数据”
做智能家居平台时,用Azure IoT Hub的设备孪生更新设备的温湿度采样vb.net教程C#教程python教程SQL教程access 2010教程间隔,结果设备一直没收到更新——查了半天发现是设备端没注册孪生回调函数,白等了3小时!后来加上回调,设备秒更采样间隔。还有一次用AWS IoT Core,规则引擎配置成把数据传到S3,但桶名写错了,导致3天的温湿度数据全丢了——后来加了规则引擎的错误日志监控,再也没出过这种低级错误。这节我把这些血泪经验揉进去,用大白话讲透Azure IoT Hub和AWS IoT Core的核心功能,结合C#实战代码逐行拆解,拓展生产级优化技巧,让你的IoT平台开发少走弯路!
二、Azure IoT Hub:微软的“物联网操作系统”,全托管高可用
Azure IoT Hub是微软提供的全托管IoT平台,核心是“设备孪生、消息路由、设备管理、DPS批量注册”,适合企业级IoT平台、智能家居、工业物联网等场景。
大白话解释:把Azure IoT Hub比作“物联网的操作系统”
1.设备孪生:设备的“数字身份证+配置中心”,云端存设备的配置(比如采样间隔),设备端同步配置,还能上报设备状态(比如信号强度);
2.消息路由:把设备消息自动转发到Event Hub、Blob Storage、SQL Database,不用自己写转发逻辑;
3.DPS(设备预配服务):批量注册百万级设备,不用手动生成每个设备的连接字符串;
4.设备管理:远程重启设备、升级固件、监控设备状态,像管理电脑一样管理IoT设备。
我踩过的坑:一开始用Azure IoT Hub的免费层,上线后消息量超过8000条/天,直接被限流了——后来换成标准层,配置消息路由到Event Hub,支持百万级消息吞吐量!
实战1:C# Azure IoT Hub设备端+云端完整代码
步骤1:准备Azure IoT Hub资源
1.登录Azure门户,创建IoT Hub;
2.在IoT Hub中创建一个设备,获取设备连接字符串;
3.安装Azure IoT SDK for .NET:
bash
# 设备端SDK
Install-Package Microsoft.Azure.Devices.Client
# 云端SDK(可选)
Install-Package Microsoft.Azure.Devices
步骤2:设备端代码(上报数据+接收孪生更新)
csharp
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Client;
using Microsoft.Azure.Devices.Shared;
using Newtonsoft.Json;
namespace IoTPlatform.AzureIoTHub.Device;
public class AzureIoTHubDeviceClient
{
private DeviceClient _deviceClient;
private readonly string _connectionString = "HostName=your-hub.azure-devices.net;DeviceId=your-device;SharedAccessKey=your-key"; // 替换成你的设备连接字符串
private int _sampleInterval = 5; // 默认采样间隔5秒
// 初始化设备客户端
public async Task InitializeAsync()
{
try
{
// 1. 创建设备客户端,用MQTT协议(推荐,比HTTP高效)
_deviceClient = DeviceClient.CreateFromConnectionString(_connectionString, TransportType.Mqtt);
await _deviceClient.OpenAsync();
Console.WriteLine("Azure IoT Hub设备端初始化成功");
// 2. 注册设备孪生回调,接收云端的配置更新
await _deviceClient.SetDesiredPropertyUpdateCallbackAsync(OnDesiredPropertyChanged, null);
// 3. 上报设备初始状态到孪生
await ReportDeviceStatusAsync();
}
catch (Exception ex)
{
Console.WriteLine($"设备端初始化失败:{ex.Message}");
}
}
// 上报温湿度数据
public async Task SendTelemetryDataAsync(CancellationToken ct)
{
Random random = new Random();
while (!ct.IsCancellationRequested)
{
try
{
// 模拟温湿度数据
var telemetry = new
{
Temperature = random.Next(20, 30) + random.NextDouble(),
Humidity = random.Next(40, 60) + random.NextDouble(),
DeviceId = "livingroom-sensor-001"
};
string payload = JsonConvert.SerializeObject(telemetry);
var message = new Message(Encoding.UTF8.GetBytes(payload))
{
ContentType = "application/json",
ContentEncoding = "utf-8",
MessageId = Guid.NewGuid().ToString()
};
// 4. 发送消息到IoT Hub
await _deviceClient.SendEventAsync(message);
Console.WriteLine($"上报数据:{payload}");
// 按孪生配置的采样间隔等待
await Task.Delay(TimeSpan.FromSeconds(_sampleInterval), ct);
}
catch (Exception ex)
{
Console.WriteLine($"上报数据失败:{ex.Message}");
await Task.Delay(1000, ct);
}
}
}
// 设备孪生回调:接收云端的配置更新
private async Task OnDesiredPropertyChanged(TwinCollection desiredProperties, object userContext)
{
Console.WriteLine($"收到孪生配置更新:{JsonConvert.SerializeObject(desiredProperties)}");
// 5. 更新本地采样间隔
if (desiredProperties.Contains("SampleInterval"))
{
_sampleInterval = desiredProperties["SampleInterval"];
Console.WriteLine($"更新采样间隔为 {_sampleInterval} 秒");
}
// 6. 上报配置更新状态到孪生的reported属性
var reportedProperties = new TwinCollection();
reportedProperties["SampleInterval"] = _sampleInterval;
reportedProperties["LastUpdatedTime"] = DateTime.UtcNow.ToString("o");
await _deviceClient.UpdateReportedPropertiesAsync(reportedProperties);
Console.WriteLine($"上报配置状态成功:{JsonConvert.SerializeObject(reportedProperties)}");
}
// 上报设备状态到孪生
private async Task ReportDeviceStatusAsync()
{
var reportedProperties = new TwinCollection();
reportedProperties["SignalStrength"] = -50; // 模拟WiFi信号强度
reportedProperties["FirmwareVersion"] = "v1.0.0";
await _deviceClient.UpdateReportedPropertiesAsync(reportedProperties);
Console.WriteLine($"上报设备状态成功:{JsonConvert.SerializeObject(reportedProperties)}");
}
// 关闭客户端
public async Task CloseAsync()
{
await _deviceClient.CloseAsync();
_deviceClient.Dispose();
Console.WriteLine("Azure IoT Hub设备端已关闭");
}
}
// 设备端测试代码
class DeviceProgram
{
static async Task Main(string[] args)
{
var deviceClient = new AzureIoTHubDeviceClient();
await deviceClient.InitializeAsync();
var cts = new CancellationTokenSource();
_ = deviceClient.SendTelemetryDataAsync(cts.Token);
Console.WriteLine("按任意键退出...");
Console.ReadKey();
cts.Cancel();
await deviceClient.CloseAsync();
}
}
步骤3:云端代码(更新设备孪生+监控设备状态)
csharp
using System;
using System.Threading.Tasks;
using Microsoft.Azure.Devices;
using Newtonsoft.Json;
namespace IoTPlatform.AzureIoTHub.Cloud;
public class AzureIoTHubCloudClient
{
private RegistryManager _registryManager;
private readonly string _connectionString = "HostName=your-hub.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=your-key"; // 替换成你的IoT Hub连接字符串
private readonly string _deviceId = "livingroom-sensor-001";
// 初始化云端客户端
public async Task InitializeAsync()
{
_registryManager = RegistryManager.CreateFromConnectionString(_connectionString);
Console.WriteLine("Azure IoT Hub云端客户端初始化成功");
}
// 更新设备孪生的desired属性
public async Task UpdateDeviceTwinAsync(int sampleInterval)
{
try
{
var twin = await _registryManager.GetTwinAsync(_deviceId);
var desiredProperties = new TwinCollection();
desiredProperties["SampleInterval"] = sampleInterval;
// 7. 合并更新孪生的desired属性,不会覆盖其他属性
await _registryManager.UpdateTwinAsync(_deviceId, twin.Tags, desiredProperties);
Console.WriteLine($"更新设备孪生成功:SampleInterval={sampleInterval}");
}
catch (Exception ex)
{
Console.WriteLine($"更新设备孪生失败:{ex.Message}");
}
}
// 获取设备孪生的reported属性
public async Task GetDeviceTwinAsync()
{
try
{
var twin = await _registryManager.GetTwinAsync(_deviceId);
Console.WriteLine($"设备孪生reported属性:{JsonConvert.SerializeObject(twin.ReportedProperties)}");
Console.WriteLine($"设备孪生desired属性:{JsonConvert.SerializeObject(twin.DesiredProperties)}");
}
catch (Exception ex)
{
Console.WriteLine($"获取设备孪生失败:{ex.Message}");
}
}
// 关闭客户端
public void Close()
{
_registryManager.Dispose();
Console.WriteLine("Azure IoT Hub云端客户端已关闭");
}
}
// 云端测试代码
class CloudProgram
{
static async Task Main(string[] args)
{
var cloudClient = new AzureIoTHubCloudClient();
await cloudClient.InitializeAsync();
await cloudClient.UpdateDeviceTwinAsync(10); // 更新采样间隔为10秒
await cloudClient.GetDeviceTwinAsync();
cloudClient.Close();
}
}
逐行拆解核心代码:
1.设备端初始化:用MQTT协议创建DeviceClient,比HTTP高效10倍;
2.孪生回调:注册SetDesiredPropertyUpdateCallbackAsync,接收云端的配置更新;
3.上报数据:发送JSON格式的消息,设置ContentType和MessageId,方便路由和监控;
4.云端更新孪生:用UpdateTwinAsync合并更新desired属性,不会覆盖设备上报的reported属性;
5.状态上报:设备端把信号强度、固件版本上报到孪生的reported属性,云端可以实时查看设备状态。
Azure IoT Hub生产级优化技巧
1.批量注册设备:用DPS(设备预配服务)批量注册百万级设备,不用手动生成每个设备的连接字符串;
2.消息路由优化:按消息类型路由,比如把告警消息转发到Event Hub,把历史数据转发到Blob Storage;
3.成本优化:用标准层的消息路由代替云端转发,减少云端计算成本;免费层适合测试,生产用标准层;
4.监控告警:配置Azure Monitor,监控设备连接数、消息延迟、错误率,设置告警阈值(比如设备离线10分钟告警);
5.固件升级:用Azure IoT Hub的设备管理功能远程升级固件,支持断点续传、回滚机制。
三、AWS IoT Core:亚马逊的“物联网数据枢纽”,云原生生态完善
AWS IoT Core是亚马逊提供的全托管IoT平台,核心是“设备影子、规则引擎、Greengrass、证书认证”,适合云原生物联网、车联网、边缘计算等场景。
大白话解释:把AWS IoT Core比作“物联网的数据枢纽”
1.设备影子:和Azure的设备孪生类似,云端存设备的配置和状态,设备端同步;
2.规则引擎:把设备消息自动转发到S3、DynamoDB、Lambda、Kinesis,支持SQL-like语法过滤消息;
3.Greengrass:边缘计算框架,把AWS服务(比如Lambda、S3)部署到边缘设备,减少云端依赖;
4.证书认证:每个设备用X.509证书认证,比用户名密码更安全,还能自动轮换证书。
我踩过的坑:一开始用AWS IoT Core的MQTT over TCP,结果设备在某些网络环境下连不上——后来换成MQTT over WebSocket,支持代理和防火墙,连接成功率直接到100%!
实战2:C# AWS IoT Core设备端+云端完整代码
步骤1:准备AWS IoT Core资源
1.登录AWS控制台,创建IoT Core;
2.在IoT Core中创建一个事物(Thing),生成设备证书和政策;
3.安装AWS SDK for .NET:
bash
Install-Package AWSSDK.IoT
Install-Package AWSSDK.IoTData
步骤2:设备端代码(上报数据+接收影子更新)
csharp
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Amazon;
using Amazon.IoTData;
using Amazon.IoTData.Model;
using Newtonsoft.Json;
namespace IoTPlatform.AwsIotCore.Device;
public class AwsIotCoreDeviceClient
{
private AmazonIoTDataClient _iotDataClient;
private readonly string _endpoint = "your-account-ats.iot.us-east-1.amazonaws.com"; // 替换成你的IoT Core端点
private readonly string _thingName = "livingroom-sensor-001";
private int _sampleInterval = 5; // 默认采样间隔5秒
// 初始化设备客户端(用证书认证)
public void Initialize()
{
try
{
// 8. 用证书和私钥创建客户端,支持MQTT over WebSocket
var config = new AmazonIoTDataConfig
{
RegionEndpoint = RegionEndpoint.USEast1,
ServiceURL = $"https://{_endpoint}"
};
// 生产环境用证书认证,这里简化用默认凭证(测试用)
_iotDataClient = new AmazonIoTDataClient(config);
Console.WriteLine("AWS IoT Core设备端初始化成功");
// 9. 订阅设备影子更新主题
SubscribeToShadowUpdatesAsync();
}
catch (Exception ex)
{
Console.WriteLine($"设备端初始化失败:{ex.Message}");
}
}
// 上报温湿度数据
public async Task SendTelemetryDataAsync(CancellationToken ct)
{
Random random = new Random();
while (!ct.IsCancellationRequested)
{
try
{
var telemetry = new
{
Temperature = random.Next(20, 30) + random.NextDouble(),
Humidity = random.Next(40, 60) + random.NextDouble(),
ThingName = _thingName
};
string payload = JsonConvert.SerializeObject(telemetry);
// 10. 发布消息到MQTT主题
var request = new PublishRequest
{
Topic = $"devices/{_thingName}/telemetry",
Payload = Encoding.UTF8.GetBytes(payload),
Qos = 1 // 至少一次送达
};
await _iotDataClient.PublishAsync(request);
Console.WriteLine($"上报数据:{payload}");
await Task.Delay(TimeSpan.FromSeconds(_sampleInterval), ct);
}
catch (Exception ex)
{
Console.WriteLine($"上报数据失败:{ex.Message}");
await Task.Delay(1000, ct);
}
}
}
// 订阅设备影子更新
private async Task SubscribeToShadowUpdatesAsync()
{
// AWS IoT影子的更新主题是$aws/things/{thingName}/shadow/update/accepted
var topic = $"$aws/things/{_thingName}/shadow/update/accepted";
// 生产环境用MQTT客户端订阅,这里简化用轮询(测试用)
while (true)
{
try
{
// 11. 轮询影子更新(生产环境用MQTT客户端的订阅回调)
var getShadowRequest = new GetThingShadowRequest { ThingName = _thingName };
var response = await _iotDataClient.GetThingShadowAsync(getShadowRequest);
var shadow = JsonConvert.DeserializeObject<dynamic>(Encoding.UTF8.GetString(response.Payload.ToArray()));
if (shadow.state.desired.SampleInterval != null)
{
_sampleInterval = shadow.state.desired.SampleInterval;
Console.WriteLine($"更新采样间隔为 {_sampleInterval} 秒");
}
await Task.Delay(5000);
}
catch (Exception ex)
{
Console.WriteLine($"获取影子失败:{ex.Message}");
await Task.Delay(5000);
}
}
}
// 关闭客户端
public void Close()
{
_iotDataClient.Dispose();
Console.WriteLine("AWS IoT Core设备端已关闭");
}
}
// 设备端测试代码
class DeviceProgram
{
static async Task Main(string[] args)
{
var deviceClient = new AwsIotCoreDeviceClient();
deviceClient.Initialize();
var cts = new CancellationTokenSource();
_ = deviceClient.SendTelemetryDataAsync(cts.Token);
Console.WriteLine("按任意键退出...");
Console.ReadKey();
cts.Cancel();
deviceClient.Close();
}
}
步骤3:云端代码(更新设备影子+配置规则引擎)
csharp
using System;
using System.Text;
using System.Threading.Tasks;
using Amazon;
using Amazon.IoT;
using Amazon.IoT.Model;
using Newtonsoft.Json;
namespace IoTPlatform.AwsIotCore.Cloud;
public class AwsIotCoreCloudClient
{
private AmazonIoTClient _iotClient;
private readonly string _thingName = "livingroom-sensor-001";
// 初始化云端客户端
public void Initialize()
{
_iotClient = new AmazonIoTClient(RegionEndpoint.USEast1);
Console.WriteLine("AWS IoT Core云端客户端初始化成功");
}
// 更新设备影子
public async Task UpdateThingShadowAsync(int sampleInterval)
{
try
{
var shadowState = new
{
state = new
{
desired = new
{
SampleInterval = sampleInterval
}
}
};
string payload = JsonConvert.SerializeObject(shadowState);
var request = new UpdateThingShadowRequest
{
ThingName = _thingName,
Payload = Encoding.UTF8.GetBytes(payload)
};
await _iotClient.UpdateThingShadowAsync(request);
Console.WriteLine($"更新设备影子成功:SampleInterval={sampleInterval}");
}
catch (Exception ex)
{
Console.WriteLine($"更新设备影子失败:{ex.Message}");
}
}
// 配置规则引擎:把温湿度数据转发到S3
public async Task CreateRuleAsync()
{
try
{
var request = new CreateTopicRuleRequest
{
RuleName = "TelemetryToS3",
TopicRulePayload = new TopicRulePayload
{
Sql = "SELECT * FROM 'devices/+/telemetry' WHERE Temperature > 28", // SQL-like语法过滤高温消息
Actions = new System.Collections.Generic.List<Action>
{
new Action
{
S3 = new S3Action
{
BucketName = "your-iot-telemetry-bucket", // 替换成你的S3桶名
Key = "telemetry/${timestamp}/${topic()}.json",
RoleArn = "arn:aws:iam::your-account-id:role/IoTToS3Role" // 替换成你的IAM角色ARN
}
}
},
RuleDisabled = false
}
};
await _iotClient.CreateTopicRuleAsync(request);
Console.WriteLine("创建规则引擎成功:高温消息转发到S3");
}
catch (Exception ex)
{
Console.WriteLine($"创建规则引擎失败:{ex.Message}");
}
}
// 关闭客户端
public void Close()
{
_iotClient.Dispose();
Console.WriteLine("AWS IoT Core云端客户端已关闭");
}
}
// 云端测试代码
class CloudProgram
{
static async Task Main(string[] args)
{
var cloudClient = new AwsIotCoreCloudClient();
cloudClient.Initialize();
await cloudClient.UpdateThingShadowAsync(10);
await cloudClient.CreateRuleAsync();
cloudClient.Close();
}
}
逐行拆解核心代码:
1.设备端初始化:用MQTT over WebSocket,支持代理和防火墙,连接成功率更高;
2.设备影子:订阅影子更新主题,同步云端的配置;生产环境用MQTT客户端的订阅回调,不用轮询;
3.规则引擎:用SQL-like语法过滤消息,比如只转发温度>28°C的告警消息到S3;
4.证书认证:生产环境用X.509证书认证,AWS IoT Core自动轮换证书,避免证书过期导致设备离线。
AWS IoT Core生产级优化技巧
1.MQTT over WebSocket:代替TCP,支持代理和防火墙,适合复杂网络环境;
2.规则引擎优化:用SQL过滤减少转发的数据量,比如只转发告警消息,不转发正常数据;
3.边缘计算:用Greengrass把Lambda部署到边缘设备,处理本地数据,减少云端带宽消耗;
4.证书自动轮换:配置AWS IoT Core的证书轮换规则,自动更新设备证书,避免证书过期;
5.监控告警:用CloudWatch监控设备连接数、消息延迟、规则引擎错误,设置告警阈值;
6.成本优化:用DynamoDB的按需模式存储设备状态,用S3的智能分层存储历史数据,降低存储成本。
四、Azure IoT Hub vs AWS IoT Core选型指南
| 维度 | Azure IoT Hub | AWS IoT Core |
|---|---|---|
| 生态 | 集成Azure服务(Event Hub、SQL、Power BI) | 集成AWS服务(S3、DynamoDB、Lambda、Greengrass) |
| 边缘计算 | Azure IoT Edge | AWS Greengrass |
| 批量注册 | DPS AWS IoT | Core注册组 |
| 认证方式 | 连接字符串、X.509证书 | X.509证书、自定义认证 |
| 计费方式 | 按消息数、设备连接数 | 按消息数、设备连接数、规则引擎执行次数 |
| 适合场景 | 企业级IoT平台、Windows设备、工业物联网 | 云原生物联网、车联网、边缘计算、Linux设备 |
选型建议
1.如果你已经用Azure服务(比如Azure SQL、Power BI),选Azure IoT Hub,集成更方便;
2.如果你用AWS云原生服务(比如Lambda、Kinesis),选AWS IoT Core,生态更完善;
3.边缘计算场景选AWS Greengrass,功能更强大;工业物联网选Azure IoT Hub,设备管理更成熟。
五、总结
Azure IoT Hub是企业级IoT平台的首选,全托管高可用,设备管理功能成熟;AWS IoT Core是云原生物联网的首选,边缘计算和规则引擎功能强大。实战中要根据业务场景选择合适的平台,注意生产级优化,比如批量注册设备、监控告警、成本优化,还要避免踩过的坑,比如Azure免费层限流、AWS证书过期、规则引擎配置错误。
下一节我们会学习IoT边缘计算,用Azure IoT Edge和AWS Greengrass把云端服务部署到边缘设备,实现本地数据处理和低延迟控制!
转载请注明出处:










