目录
- 一、腾讯云平台项目创建
- 1.新建项目
- 2.新建产品
- 3.新建设备
- 二、基于TCP的MQTT接入
- 1.接入介绍
- 2.用户名格式
- 3.密码格式
- 4.通过python生成用户名和密码
- 三、ESP32代码
- 1.MQTT API参考
- 2.代码实现
- 3.结果查看
一、腾讯云平台项目创建
1.新建项目
微信扫码登入腾讯云平台,进入控制台->物联网开发平台。
选择公共实例
输入项目名称,保存后可以看到新创建的项目
2.新建产品
进入新建的项目中,点击新建产品,连接方式选择WIFI。认证方式选择密钥认证
保存后可以看到产品列表已经有数据了
3.新建设备
产品创建完毕之后,可以看到产品的各种设置,这里选择设备调试->新建设备
新建完毕之后,可以查看设备三元组,这是MQTT密钥用户名和密码生成的关键
到此,项目已经完成创建。
二、基于TCP的MQTT接入
1.接入介绍
根据腾讯云官方介绍,MQTT接入规则如下:
服务器地址:${productId}.iotcloud.tencentdevices.com
2.用户名格式
username 字段的格式为:
${productId}${deviceName};${sdkappid};${connid};${expiry}
注意:${} 表示变量,并非特定的拼接符号。
其中各字段含义如下:productId
:产品 ID。deviceName
: 设备名称。sdkappid
:固定填12010126。connid
:一个随机字符串。expiry
:表示签名的有效期, 从1970年1月1日00:00:00 UTC 时间至今秒数的 UTF8 字符串。
3.密码格式
password 字段格式为:
${token};hmac 签名方法
其中 hmac 签名方法字段填写第三步用到的摘要算法,可选的值有 hmacsha256 和 hmacsha1。
4.通过python生成用户名和密码
代码如下:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import base64
import hashlib
import hmac
import random
import string
import time
import sys
# 生成指定长度的随机字符串
def RandomConnid(length):
return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(length))
# 生成接入物联网通信平台需要的各参数
def IotHmac(productID, devicename, devicePsk):
# 1. 生成 connid 为一个随机字符串,方便后台定位问题
connid = RandomConnid(5)
# 2. 生成过期时间,表示签名的过期时间,从纪元1970年1月1日 00:00:00 UTC 时间至今秒数的 UTF8 字符串
expiry = int(time.time()) + 60 * 60 #可以改大一点
# 3. 生成 MQTT 的 clientid 部分, 格式为 ${productid}${devicename}
clientid = "{}{}".format(productID, devicename)
# 4. 生成 MQTT 的 username 部分, 格式为 ${clientid};${sdkappid};${connid};${expiry}
username = "{};12010126;{};{}".format(clientid, connid, expiry)
# 5. 对 username 进行签名,生成token
secret_key = devicePsk.encode('utf-8') # convert to bytes
data_to_sign = username.encode('utf-8') # convert to bytes
secret_key = base64.b64decode(secret_key) # this is still bytes
token = hmac.new(secret_key, data_to_sign, digestmod=hashlib.sha256).hexdigest()
# 6. 根据物联网通信平台规则生成 password 字段
password = "{};{}".format(token, "hmacsha256")
return {
"clientid" : clientid,
"username" : username,
"password" : password
}
if __name__ == '__main__':
print(IotHmac(sys.argv[1], sys.argv[2], sys.argv[3]))
如果电脑里没有python环境的可以直接使用菜鸟的python在线编译器sys.argv[1] :产品ID
sys.argv[2] :设备ID
sys.argv[3] :密钥
生成结果
{
'clientid': 'BENLB3UA1Udriver1',
'username': 'BENLB3UA1Udriver1;12010126;8MOBM;1646362197',
'password': '9d7188b616aaf81d1a2054a9bf420883a7a6addfa012e17afafe3b38a5b0c147;hmacsha256'
}
三、ESP32代码
1.MQTT API参考
头文件:components/mqtt/esp-mqtt/include/mqtt_client.h
mqtt api接口(仅列出目前使用的部分):
//创建MQTT句柄,成功返回句柄,不成功返回NULL
//config: mqtt 配置结构
esp_mqtt_client_handle_t esp_mqtt_client_init(constesp_mqtt_client_config_t *config);
//注册MQTT事件
//client: mqtt 客户端句柄
//event: 事件类型
//event_handler: 处理程序回调
//event_handler_arg: 处理程序上下文
esp_err_t esp_mqtt_client_register_event(esp_mqtt_client_handle_tclient, esp_mqtt_event_id_tevent, esp_event_handler_tevent_handler, void *event_handler_arg);
//使用已创建的客户端句柄启动 mqtt 客户端
//client: mqtt 客户端句柄
esp_err_t esp_mqtt_client_start(esp_mqtt_client_handle_tclient);
2.代码实现
提示:连接MQTT之前请先确保WIFI连接成功
mqtt宏定义:
#define MQTT_KEEPALIVE 120 //心跳
#define ClientID "BENLB3UA1Udriver1" //客户端ID
#define SERVER_IP "BENLB3UA1U.iotcloud.tencentdevices.com"//服务器IP
#define SERVER_PORT 1883 //端口号
//用户名和密码可使用python完成
#define Username "BENLB3UA1Udriver1;12010126;8MOBM;1646362197"//用户名
#define Password "9d7188b616aaf81d1a2054a9bf420883a7a6addfa012e17afafe3b38a5b0c147;hmacsha256"//密码
主函数:
void app_main(void)
{
ESP_LOGI(TAG, "[APP] Startup..");
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
esp_log_level_set("MQTT_EXAMPLE", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_BASE", ESP_LOG_VERBOSE);
esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(example_connect());//官方测试用wifi连接函数,一般不使用
mqtt_app_start();
}
mqtt函数:
static void mqtt_app_start(void)
{
esp_mqtt_client_config_t mqtt_cfg = {
.host = SERVER_IP, //MQTT 地址
.port = SERVER_PORT, //MQTT端口
.client_id = ClientID, //连接ID
.keepalive = MQTT_KEEPALIVE, //心跳时间
.username = Username, //用户名字
.password = Password, //密码
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);//句柄创建
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(client);
}
事件回调:
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
esp_mqtt_event_handle_t event = event_data;
esp_mqtt_client_handle_t client = event->client;
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED: //连接成功
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
break;
case MQTT_EVENT_DISCONNECTED: //断开连接
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED: //订阅
break;
case MQTT_EVENT_UNSUBSCRIBED: //取消订阅
break;
case MQTT_EVENT_PUBLISHED: //发布
break;
case MQTT_EVENT_DATA: //订阅消息
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR: //错误
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
}
3.结果查看
提示:本篇仅作为学习记录,切勿当做标准教程,如有错误,欢迎提出指正。