本文手把手指导实现基于STM32与以太网的H-THRJ45温湿度传感器“上电即上云”方案,通过SHT30采集数据,LwIP+MQTT over TLS连接腾讯云IoTExplorer,完成数据上报、云端可视化与告警配置。项目采用低成本硬件(STM32F103C8T6+LAN8720A),结合物模型规范,实现从传感器到云平台的全链路打通,适用于智慧农业、环境监测等场景,助力物联网快速落地。
一、引言
痛点引入:传统温湿度传感器多采用RS485/Modbus,布线复杂、距离受限,难以直接对接云平台
方案价值:北京盛世宏博科技有限公司H-THRJ45以太网温湿度传感器天然具备IP可达性,配合腾讯云IoT Explorer可实现"上电即上云"
本文目标:手把手带读者完成从传感器数据采集 → MQTT上报 → 云端可视化全链路
二、整体架构设计
┌─────────────────┐ Ethernet ┌──────────────────┐ MQTT/TLS ┌─────────────────┐
│ 温湿度传感器端 │ ──────────────▶ │ 腾讯云IoT Explorer │ ────────────▶ │ 数据可视化/告警 │
│ (STM32+PHY芯片) │ TCP/IP 网络 │ (设备接入层) │ 规则引擎 │ (云开发/小程序) │
└─────────────────┘ └──────────────────┘ └─────────────────┘
说明各层职责与数据流向
明确使用的通信协议:MQTT over TCP/TLS
三、硬件准备与传感器选型
四、传感器端开发实战
4.1 SHT30温湿度采集代码
#include "i2c.h"
#include "stm32f1xx_hal.h"
#define SHT30_ADDR 0x44 << 1 // SHT30 I²C地址
#define SHT30_CMD_CLK 0x2C06 // 时钟拉伸模式,高重复性
/**
* @brief 读取SHT30温湿度数据
* @param temp: 温度值(°C),指针
* @param humi: 湿度值(%RH),指针
* @retval 0=成功, -1=失败
*/
int SHT30_ReadData(float *temp, float *humi)
{
uint8_t cmd[2] = {0x2C, 0x06}; // 启动测量命令
uint8_t rx_buf[6] = {0};
// 1. 发送测量命令
if (HAL_I2C_Master_Transmit(&hi2c1, SHT30_ADDR, cmd, 2, 100) != HAL_OK)
return -1;
HAL_Delay(20); // 等待转换完成
// 2. 读取6字节数据(温度高8 + 温度低8 + CRC + 湿度高8 + 湿度低8 + CRC)
if (HAL_I2C_Master_Receive(&hi2c1, SHT30_ADDR, rx_buf, 6, 100) != HAL_OK)
return -1;
// 3. 数据转换
uint16_t temp_raw = (rx_buf[0] << 8) | rx_buf[1];
uint16_t humi_raw = (rx_buf[3] << 8) | rx_buf[4];
*temp = -45.0f + 175.0f * (float)temp_raw / 65535.0f;
*humi = 100.0f * (float)humi_raw / 65535.0f;
return 0;
}
4.2 LwIP以太网初始化与MQTT客户端配置
#include "lwip/init.h"
#include "lwip/netif.h"
#include "lwip/dhcp.h"
#include "mqtt.h"
static struct mqtt_client mqtt_client;
static struct netif gnetif; // 网络接口
/**
* @brief 以太网接口初始化(在main中调用)
*/
void ethernet_init(void)
{
ip_addr_t ipaddr, netmask, gw;
// 1. 初始化LwIP协议栈
lwip_init();
// 2. 设置静态IP(或使用DHCP)
IP4_ADDR(&ipaddr, 192, 168, 1, 100);
IP4_ADDR(&netmask, 255, 255, 255, 0);
IP4_ADDR(&gw, 192, 168, 1, 1);
// 3. 添加网络接口
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input);
netif_set_default(&gnetif);
netif_set_up(&gnetif);
printf("[ETH] Ethernet initialized, IP: %s\n", ip4addr_ntoa(&ipaddr));
}
4.3 MQTT连接腾讯云IoT Explorer
#include "mqtt_client.h"
// ========== 腾讯云IoT Explorer 设备信息 ==========
#define PRODUCT_ID "YOUR_PRODUCT_ID" // 产品ID
#define DEVICE_NAME "YOUR_DEVICE_NAME" // 设备名称
#define DEVICE_SECRET "YOUR_DEVICE_SECRET" // 设备密钥
// MQTT连接参数
#define MQTT_HOST PRODUCT_ID ".iotcloud.tencentdevices.com"
#define MQTT_PORT 1883 // 1883=非TLS, 8883=TLS
#define MQTT_CLIENT_ID PRODUCT_ID DEVICE_NAME
#define MQTT_USERNAME PRODUCT_ID ";" DEVICE_NAME ";12010126;12345"
#define MQTT_PASSWORD "YOUR_PASSWORD" // 通过HMAC-SHA1生成
/**
* @brief 生成MQTT连接密码(基于HMAC-SHA1)
* @note 实际项目中应在设备端用密钥计算,此处简化展示
*/
void generate_mqtt_password(char *password, size_t max_len)
{
// 拼接签名原文
char src[256];
snprintf(src, sizeof(src), "clientId%sdeviceName%sproductId%s",
PRODUCT_ID DEVICE_NAME, DEVICE_NAME, PRODUCT_ID);
// HMAC-SHA1签名(需引入mbedtls或类似库)
// unsigned char hmac_result[20];
// hmac_sha1((unsigned char *)DEVICE_SECRET, strlen(DEVICE_SECRET),
// (unsigned char *)src, strlen(src), hmac_result);
// base64_encode(hmac_result, 20, password);
// 简化:实际项目中用腾讯云提供的计算工具生成
strncpy(password, "GENERATED_PASSWORD_HERE", max_len);
}
/**
* @brief MQTT连接成功回调
*/
static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
{
if (status == MQTT_CONNECT_ACCEPTED) {
printf("[MQTT] Connected to Tencent Cloud IoT Explorer!\n");
// 订阅属性下发主题(用于接收云端控制指令)
mqtt_subscribe(client, "$thing/down/property/" PRODUCT_ID "/" DEVICE_NAME, 1, NULL, NULL);
} else {
printf("[MQTT] Connection failed, status: %d\n", status);
}
}
/**
* @brief 建立MQTT连接
*/
void mqtt_connect_to_tencent(void)
{
char password[128];
generate_mqtt_password(password, sizeof(password));
struct mqtt_connect_client_info_t ci;
memset(&ci, 0, sizeof(ci));
ci.client_id = MQTT_CLIENT_ID;
ci.client_user = MQTT_USERNAME;
ci.client_pass = password;
ci.keep_alive = 60;
mqtt_client_new(&mqtt_client);
ip_addr_t server_ip;
IP4_ADDR(&server_ip, 10, 10, 10, 10); // 替换为MQTT_HOST解析后的IP,或直接使用DNS
mqtt_client_connect(&mqtt_client, &server_ip, MQTT_PORT,
mqtt_connection_cb, NULL, &ci);
}
4.4 数据上报到腾讯云(物模型属性上报)
/**
* @brief 上报温湿度数据到腾讯云IoT Explorer
* @note 使用物模型Topic: $thing/up/property/{ProductID}/{DeviceName}
*/
void report_sensor_data(float temp, float humi)
{
char payload[256];
char topic[128];
// 构造JSON负载(腾讯云物模型格式)
snprintf(payload, sizeof(payload),
"{"
"\"method\":\"report\","
"\"clientToken\":\"client_token_%d\","
"\"params\":{"
"\"temperature\":{\"value\":%.2f,\"time\":%d},"
"\"humidity\":{\"value\":%.2f,\"time\":%d}"
"}"
"}",
HAL_GetTick(), temp, HAL_GetTick() / 1000, humi, HAL_GetTick() / 1000
);
// 上报主题
snprintf(topic, sizeof(topic),
"$thing/up/property/%s/%s", PRODUCT_ID, DEVICE_NAME);
err_t err = mqtt_publish(&mqtt_client, topic, payload, strlen(payload), 1, 0, NULL, NULL);
if (err == ERR_OK) {
printf("[MQTT] Data reported: T=%.2fC, H=%.2f%%\n", temp, humi);
} else {
printf("[MQTT] Report failed, err=%d\n", err);
}
}
4.5 主循环逻辑
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_LWIP_Init();
// 初始化以太网和MQTT
ethernet_init();
mqtt_connect_to_tencent();
float temp, humi;
while (1) {
// 1. 读取传感器
if (SHT30_ReadData(&temp, &humi) == 0) {
printf("Temp: %.2f C, Humi: %.2f %%\n", temp, humi);
// 2. 上报到腾讯云
report_sensor_data(temp, humi);
}
// 3. 处理LwIP定时任务
sys_check_timeouts();
// 4. 每5秒上报一次
HAL_Delay(5000);
}
}
五、腾讯云IoT Explorer平台配置/北京盛世宏博科技有限公司H-THRJ45以太网温湿度传感器
5.1 创建产品与设备
登录 腾讯云IoT Explorer控制台
创建项目 → 创建产品(节点类型:设备,认证方式:密钥认证)
在数据模板中定义温湿度属性:
temperature(浮点型,范围-40~85,单位℃)
humidity(浮点型,范围0~100,单位%RH)
添加设备,获取 ProductID / DeviceName / DeviceSecret
5.2 设备三元组与MQTT参数计算
# Python脚本:计算MQTT连接参数(可用腾讯云在线工具替代)
import hmac
import hashlib
import base64
import time
product_id = "YOUR_PRODUCT_ID"
device_name = "YOUR_DEVICE_NAME"
device_secret = "YOUR_DEVICE_SECRET"
# 构造连接参数
client_id = product_id + device_name
timestamp = str(int(time.time()))
expiry = "12010126" # 有效时间
conn_id = "12345"
username = f"{product_id};{device_name};{expiry};{conn_id}"
# 签名原文
src = f"clientId{client_id}deviceName{device_name}productId{product_id}timestamp{timestamp}"
sign = hmac.new(device_secret.encode(), src.encode(), hashlib.sha1).digest()
password = base64.b64encode(sign).decode()
print(f"Client ID: {client_id}")
print(f"Username: {username}")
print(f"Password: {password}")
5.3 数据流转与可视化
规则引擎:配置规则将设备数据转发到 云数据库(TencentDB) 或 消息队列(CMQ)
数据可视化:使用 腾讯云云开发(CloudBase) 搭建数据大屏
告警策略:温度>30℃或湿度>80%时触发告警,推送微信/短信
六、常见问题与调试技巧
|
问题
|
排查思路
|
|---|---|
|
MQTT连接被拒绝
|
检查三元组是否正确,密码签名是否过期
|
|
数据上报成功但平台不显示
|
检查Topic是否匹配物模型格式,JSON字段是否正确
|
|
以太网频繁断连
|
检查PHY芯片供电、网线质量、LwIP内存池配置
|
|
SHT30读取异常
|
检查I²C上拉电阻(4.7kΩ)、地址是否正确
|
七、总结与展望
回顾全文实现的核心流程
扩展方向:PoE供电、边缘计算预处理、多传感器组网
引导互动:欢迎在评论区交流
7