目录
1.创建产品和设备
1.1 创建产品
进入阿里云物联网平台-->点击右上角的控制台-->搜索“物联网平台”-->点击公共实例:
选择设备管理-->产品-->创建产品:
1.2 创建设备
1.3 复制设备三要素
按以下操作获取设备三要素(ProductKey、DeviceName、DeviceSecret):
1.4 下载阿里云物联网平台自签名证书
到这里去下载 阿里云物联网平台自签名证书
2.创建工程
2.1 创建基础工程
以hello world例程为基础,新建一个工程,并保存在一个路径:
创建完成后先编译一下。
3.修改代码
3.1 修改 main.c
将 hello_world_main.c 改成 main.c,并删除原本代码,用以下代码替换,先初始化WiFi,然后等WiFi连接后再启动MQTT:
#include "mqtt_aliot.h"
#include "wifi.h"
#include "esp_log.h"
#define TAG "main"
void app_main(void)
{
/* 初始化WIFI */
wifi_configuration();
/* 等待信号量(WiFi连接成功后会释放信号量),启动MQTT */
xSemaphoreTake(s_wifi_connect_sem, portMAX_DELAY);
mqtt_start();
ESP_LOGI(TAG, "hello world!");
while(1)
{
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
3.2 编写 WiFi 连接功能
创建wifi.c和wifi.h两个文件,并编写代码实现WiFi功能。
3.2.1 初始化WiFi相关配置
(1)初始化nvs
当初始化wifi热点和密码后,IDF会将其保存到nvs中:
ESP_ERROR_CHECK(nvs_flash_init());
(2)初始化lwip
ESP_ERROR_CHECK(esp_netif_init());
(3)创建事件系统循环
ESP_ERROR_CHECK(esp_event_loop_create_default());
(4)创建STA
esp_netif_create_default_wifi_sta();
(5)初始化wifi
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
(6)注册事件响应
//创建二值信号量,用于WiFi连接后启动MQTT客户端
s_wifi_connect_sem = xSemaphoreCreateBinary();
//注册WIFI事件
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL);
//注册网络事件
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL);
(7) 配置sta参数
/* 配置wifi,用于设置sta参数 */
wifi_config_t wifi_config = {
.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK, //加密方式
.sta.pmf_cfg.capable = true, //是否启用保护管理帧,选择启用
.sta.pmf_cfg.required = false, //是否只和有保护管理帧功能的设备通信,选择否
.sta.ssid = TEST_SSID, //WIFI热点名称
.sta.password = TEST_PASSID, //WIFI热点密码
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));//设为sta模式
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));//配置sta参数
(8)启动WiFi
ESP_ERROR_CHECK(esp_wifi_start());
(9)编写WiFi事件回调函数
启动了sta模式后则连接WiFi,获取到IP地址后则释放信号量,允许启动MQTT客户端:
void wifi_event_handler(void *event_handler_arg,
esp_event_base_t event_base,
int32_t event_id,
void *event_data)
{
if (event_base == WIFI_EVENT)
{
switch (event_id)
{
case WIFI_EVENT_STA_START://启动了wifi的sta工作模式
esp_wifi_connect();//连接wifi
break;
case WIFI_EVENT_STA_CONNECTED:
ESP_LOGI(TAG, "esp32 connected to ap!");
break;
case WIFI_EVENT_STA_DISCONNECTED:
ESP_LOGI(TAG, "esp32 connected the ap failed! retry");
esp_wifi_connect();
break;
default: break;
}
}
else if (event_base == IP_EVENT)
{
switch (event_id)
{
case IP_EVENT_STA_GOT_IP: //获取到ip地址
ESP_LOGI(TAG, "esp32 get ip address!");
xSemaphoreGive(s_wifi_connect_sem);//释放信号量,允许启动mqtt客户端
break;
}
}
}
3.2.2 完整代码
wifi.h完整代码:
#ifndef _WIFI_H_
#define _WIFI_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_event.h"
#include "freertos/semphr.h"
extern SemaphoreHandle_t s_wifi_connect_sem;
void wifi_configuration(void);
#ifdef __cplusplus
}
#endif
#endif
wifi.c完整代码:
#include "wifi.h"
#include <stdio.h>
#include <string.h>
#include "nvs_flash.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_err.h"
#include "mqtt_client.h"
#define TAG "wifi"
#define TEST_SSID "Mi 11 LE"
#define TEST_PASSID "12345678"
SemaphoreHandle_t s_wifi_connect_sem = NULL;
void wifi_event_handler(void *event_handler_arg,
esp_event_base_t event_base,
int32_t event_id,
void *event_data)
{
if (event_base == WIFI_EVENT)
{
switch (event_id)
{
case WIFI_EVENT_STA_START://启动了wifi的sta工作模式
esp_wifi_connect();//连接wifi
break;
case WIFI_EVENT_STA_CONNECTED:
ESP_LOGI(TAG, "esp32 connected to ap!");
break;
case WIFI_EVENT_STA_DISCONNECTED:
ESP_LOGI(TAG, "esp32 connected the ap failed! retry");
esp_wifi_connect();
break;
default: break;
}
}
else if (event_base == IP_EVENT)
{
switch (event_id)
{
case IP_EVENT_STA_GOT_IP: //获取到ip地址
ESP_LOGI(TAG, "esp32 get ip address!");
xSemaphoreGive(s_wifi_connect_sem);//释放信号量,允许启动mqtt客户端
break;
}
}
}
void wifi_configuration(void)
{
/* 初始化nvs(当初始化wifi热点和密码后,IDF会将其保存到nvs中) */
ESP_ERROR_CHECK(nvs_flash_init());
/* 初始化lwip */
ESP_ERROR_CHECK(esp_netif_init());
/* 创建事件系统循环 */
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* 创建STA */
esp_netif_create_default_wifi_sta();
/* 初始化wifi */
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
/* 注册事件响应 */
//创建二值信号量,用于WiFi连接后启动MQTT客户端
s_wifi_connect_sem = xSemaphoreCreateBinary();
//注册WIFI事件
esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL);
//注册网络事件
esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, wifi_event_handler, NULL);
/* 配置wifi,用于设置sta参数 */
wifi_config_t wifi_config = {
.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK, //加密方式
.sta.pmf_cfg.capable = true, //是否启用保护管理帧,选择启用
.sta.pmf_cfg.required = false, //是否只和有保护管理帧功能的设备通信,选择否
.sta.ssid = TEST_SSID, //WIFI热点名称
.sta.password = TEST_PASSID, //WIFI热点密码
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));//设为sta模式
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));//配置sta参数
/* 启动wifi */
ESP_ERROR_CHECK(esp_wifi_start());
}
3.3 编写 MQTT 功能
创建mqtt_aliot.c和mqtt_aliot.h两个文件,并实现通过mqtt接入阿里云的代码
3.3.1 定义三要素和域名
将步骤1.3中获取的三要素和域名以宏定义方式放到mqtt_aliot.h中
3.3.2 将自签名证书定义成字符串
将步骤1.4中下载的阿里云物联网平台自签名证书以字符串方式定义在mqtt_aliot.c中:
3.3.3 初始化MQTT客户端(核心步骤)
核心函数:
esp_mqtt_client_handle_t esp_mqtt_client_init(const esp_mqtt_client_config_t *config)
关键步骤:需要对参数config进行初始化,先定义一个结构体mqtt_cfg
esp_mqtt_client_config_t mqtt_cfg = {0};
(1)配置域名和端口号
mqtt_cfg.broker.address.uri = ALIOT_MQTT_URL;
mqtt_cfg.broker.address.port = 8883;//注意:由于使用了阿里云平台的自签名证书,端口号需改成8883
(2)配置MQTT的CONNECT报文参数
由使用TLS加密设备和物联网平台的MQTT通信_物联网平台(IoT)-阿里云帮助中心可知,MQTT的CONNECT报文参数主要由 mqttClientId、mqttUsername、mqttPassword 三部分组成。
例如:
mqttClientId: clientId+"|securemode=3,signmethod=hmacsha1,timestamp=132323232|"
mqttUsername: deviceName+"&"+productKey
mqttPassword: sign_hmac(deviceSecret,content)
mqttClientId:格式中
| |
内为扩展参数。clientId:表示客户端ID,可自定义,这里我们使用设备的MAC地址。
securemode:表示目前安全模式,可选值有2(TLS直连模式)和3(TCP直连模式)。
signmethod:表示签名算法类型。支持hmacmd5,hmacsha1和hmacsha256。
timestamp:表示当前时间毫秒值,可以不传递。
mqttPassword:sign签名需把提交给服务器的参数按字典排序后,根据signmethod加签。签名计算示例,请参见MQTT连接签名示例。
content的值为提交给服务器的参数(productKey、deviceName、timestamp和clientId),按照参数名称首字母字典排序, 然后将参数值依次拼接。
重要
此处productKey和deviceName为必填参数,timestamp和clientId为可选参数。若传入timestamp或clientId,必须与mqttClientId中的设置相同。
①配置MQTT客户端ID(mqttClientId)
mqttClientId: clientId+"|securemode=2,signmethod=hmacmd5|"
这里选择MAC地址作为clientId,加密方式选择选择TLS直连,md5加密,不添加时间戳
功能实现:
//mqttClientId: clientId+"|securemode=3,signmethod=hmacsha1,timestamp=132323232|"
char client_id[128];
snprintf(client_id, sizeof(client_id),
"%s|securemode=2,signmethod=hmacmd5|",// 选择TLS直连,md5加密
get_clientid());
mqtt_cfg.credentials.client_id = client_id;
实现具体函数功能:
/* 获取客户端ID(自定义):以MAC地址作为客户端ID */
char *get_clientid(void)
{
uint8_t mac[6];
static char client_id[32] = {0};
esp_wifi_get_mac(WIFI_IF_STA, mac);//获取mac地址
snprintf(client_id, sizeof(client_id), "%02X%02X%02X%02X%02X%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return client_id;
}
②配置MQTT用户名(mqttUsername)
mqttUsername: deviceName+"&"+productKey
其中deviceName是设备名,productKey是产品秘钥
替换后:
mqttUsername: d001&k1m123NM9XY
功能实现:
//mqttUsername: deviceName+"&"+productKey
char user_name[128];
snprintf(user_name, sizeof(user_name),"%s&%s", ALIOT_DEVICENAME, ALIOT_PRODUCTKEY);
mqtt_cfg.credentials.username = user_name;
③配置MQTT用户密码(mqttPassword)
mqttPassword: sign_hmac(deviceSecret, content)
- sign_hmac:表示一个函数,将deviceSecret和content通过哈希算法转换后,将生成的结果再转还能为十六进制返回。
- deviceSecret:是设备秘钥
- content:是提交给服务器的参数
content:clientId+X1+deviceName+X2+productKey+X3+timestamp+X4
- X1:表示步骤①中的clientId,即MAC地址(假设是1234)
- X2:表示设备名,此示例中是d001
- X3:表示设备秘钥,此示例中是k1m123NM9XY
- X4:表示时间戳,可选,此示例中未使用
替换后:
content:clientId1234deviceNamed001productKeyk1m123NM9XY
功能实现:
//mqttPassword:sign_hmac(deviceSecret, content)
char sign_content[128];
snprintf(sign_content, sizeof(sign_content), "clientId%sdeviceName%sproductKey%s",
get_clientid(), ALIOT_DEVICENAME, ALIOT_PRODUCTKEY);//获取内容
char *password_pStr = sign_hmac(ALIOT_DEVICESECRET, sign_content);
mqtt_cfg.credentials.authentication.password = password_pStr;
实现具体函数功能:
/** md5算法,散列算法的一种,用于将任意长度字符串转换为固定16位的字符串
* key: 设备秘钥
*/
void cal_md5(char *key, char *content, unsigned char *output)
{
mbedtls_md_context_t md5_ctx;
//取得指定算法的摘要信息
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
mbedtls_md_init(&md5_ctx);//初始化算法
mbedtls_md_setup(&md5_ctx, md_info, 1);//设置要指定的算法,并使用hmac算法
mbedtls_md_hmac_starts(&md5_ctx, (const unsigned char *)key, strlen(key));//开始计算
mbedtls_md_hmac_update(&md5_ctx, (const unsigned char *)content, strlen(content));
mbedtls_md_hmac_finish(&md5_ctx, (unsigned char *)output);
mbedtls_md_free(&md5_ctx);
}
/* 将16进制数转换为字符串 */
void hex2str(uint8_t *input, uint32_t input_len, char *output)
{
char *upper = "0123456789ABCDEF";
int i = 0;
int j = 0;
for (i = 0; i< input_len; i++)
{
output[j++] = upper[(input[i]>>4)&0x0F];
output[j++] = upper[(input[i])&0x0F];
}
output[j] = 0;
}
char password_buf[33];
char *sign_hmac(char *deviceScrect, char *content)
{
unsigned char password_hex[16];
cal_md5(deviceScrect, content, password_hex);//计算出16进制的密码
hex2str(password_hex, 16, password_buf);//将16进制数转换为字符串
return password_buf;
}
(3)配置阿里云物联网平台TLS自签名证书
mqtt_cfg.broker.verification.certificate = ali_iot_ca;
(4)初始化MQTT客户端
mqtt_handle = esp_mqtt_client_init(&mqtt_cfg);
3.3.4 注册事件响应回调函数
核心函数:
esp_err_t esp_mqtt_client_register_event(esp_mqtt_client_handle_t client, esp_mqtt_event_id_t event, esp_event_handler_t event_handler, void *event_handler_arg)
关键步骤:注册回调函数mqtt_event_callback
esp_mqtt_client_register_event(mqtt_handle, ESP_EVENT_ANY_ID, mqtt_event_callback, NULL);//注册事件响应回调函数
回调函数实现:
void mqtt_event_callback(void *event_handler_arg,
esp_event_base_t event_base,
int32_t event_id,
void *event_data)
{
esp_mqtt_event_handle_t data = (esp_mqtt_event_handle_t)event_data;
switch (event_id)
{
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "aliot mqtt connected");
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "aliot mqtt disconnected");
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "aliot mqtt published ack");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "aliot mqtt subcribed ack");
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "topic->%s", data->topic);
ESP_LOGI(TAG, "payload->%s", data->data);
break;
default: break;
}
}
3.3.5 启动MQTT客户端
esp_mqtt_client_start(mqtt_handle);
3.3.6 完整代码
mqtt_aliot.h完整代码:
#ifndef _MQTT_ALIOT_H_
#define _MQTT_ALIOT_H_
#define ALIOT_PRODUCTKEY "k1m123NM9XY" //产品秘钥
#define ALIOT_DEVICENAME "d001" //设备名称
#define ALIOT_DEVICESECRET "eb7a380d7c24160ec2d255cfce7bef70" //设备秘钥
//域名
// #define ALIOT_MQTT_URL "mqtts://"ALIOT_PRODUCTKEY".iot-as-mqtt.cn-shanghai.aliyuncs.com" //旧版
#define ALIOT_MQTT_URL "mqtts://iot-06z00cmxnxfz6pg.mqtt.iothub.aliyuncs.com" //新版(公版) 两版均可
/* 启动阿里云IoT连接 */
void mqtt_start(void);
#endif
mqtt_aliot.c完整代码:
#include "mqtt_aliot.h"
#include "esp_log.h"
#include "mqtt_client.h"
#include "mbedtls/md5.h"
#include "mbedtls/md.h"
#include "esp_wifi.h"
#include <stdio.h>
#define TAG "aliot"
//阿里云物联网平台自签名证书:
char *ali_iot_ca = "\"-----BEGIN CERTIFICATE-----\n"
"MIID3zCCAsegAwIBAgISfiX6mTa5RMUTGSC3rQhnestIMA0GCSqGSIb3DQEBCwUA"
"MHcxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwISGFu"
"Z3pob3UxEzARBgNVBAoMCkFsaXl1biBJb1QxEDAOBgNVBAsMB1Jvb3QgQ0ExGzAZ"
"BgNVBAMMEkFsaXl1biBJb1QgUm9vdCBDQTAgFw0yMzA3MDQwNjM2NThaGA8yMDUz"
"MDcwNDA2MzY1OFowdzELMAkGA1UEBhMCQ04xETAPBgNVBAgMCFpoZWppYW5nMREw"
"DwYDVQQHDAhIYW5nemhvdTETMBEGA1UECgwKQWxpeXVuIElvVDEQMA4GA1UECwwH"
"Um9vdCBDQTEbMBkGA1UEAwwSQWxpeXVuIElvVCBSb290IENBMIIBIjANBgkqhkiG"
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoK//6vc2oXhnvJD7BVhj6grj7PMlN2N4iNH4"
"GBmLmMdkF1z9eQLjksYc4Zid/FX67ypWFtdycOei5ec0X00m53Gvy4zLGBo2uKgi"
"T9IxMudmt95bORZbaph4VK82gPNU4ewbiI1q2loRZEHRdyPORTPpvNLHu8DrYBnY"
"Vg5feEYLLyhxg5M1UTrT/30RggHpaa0BYIPxwsKyylQ1OskOsyZQeOyPe8t8r2D4"
"RBpUGc5ix4j537HYTKSyK3Hv57R7w1NzKtXoOioDOm+YySsz9sTLFajZkUcQci4X"
"aedyEeguDLAIUKiYicJhRCZWljVlZActorTgjCY4zRajodThrQIDAQABo2MwYTAO"
"BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkWHoKi2h"
"DlS1/rYpcT/Ue+aKhP8wHwYDVR0jBBgwFoAUkWHoKi2hDlS1/rYpcT/Ue+aKhP8w"
"DQYJKoZIhvcNAQELBQADggEBADrrLcBY7gDXN8/0KHvPbGwMrEAJcnF9z4MBxRvt"
"rEoRxhlvRZzPi7w/868xbipwwnksZsn0QNIiAZ6XzbwvIFG01ONJET+OzDy6ZqUb"
"YmJI09EOe9/Hst8Fac2D14Oyw0+6KTqZW7WWrP2TAgv8/Uox2S05pCWNfJpRZxOv"
"Lr4DZmnXBJCMNMY/X7xpcjylq+uCj118PBobfH9Oo+iAJ4YyjOLmX3bflKIn1Oat"
"vdJBtXCj3phpfuf56VwKxoxEVR818GqPAHnz9oVvye4sQqBp/2ynrKFxZKUaJtk0"
"7UeVbtecwnQTrlcpWM7ACQC0OO0M9+uNjpKIbksv1s11xu0=\n"
"-----END CERTIFICATE-----";
static esp_mqtt_client_handle_t mqtt_handle = NULL;
/* 获取客户端ID(自定义):以MAC地址作为客户端ID */
char *get_clientid(void)
{
uint8_t mac[6];
static char client_id[32] = {0};
esp_wifi_get_mac(WIFI_IF_STA, mac);//获取mac地址
snprintf(client_id, sizeof(client_id), "%02X%02X%02X%02X%02X%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return client_id;
}
/** md5算法,散列算法的一种,用于将任意长度字符串转换为固定16位的字符串
* key: 设备秘钥
*/
void cal_md5(char *key, char *content, unsigned char *output)
{
mbedtls_md_context_t md5_ctx;
//取得指定算法的摘要信息
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
mbedtls_md_init(&md5_ctx);//初始化算法
mbedtls_md_setup(&md5_ctx, md_info, 1);//设置要指定的算法,并使用hmac算法
mbedtls_md_hmac_starts(&md5_ctx, (const unsigned char *)key, strlen(key));//开始计算
mbedtls_md_hmac_update(&md5_ctx, (const unsigned char *)content, strlen(content));
mbedtls_md_hmac_finish(&md5_ctx, (unsigned char *)output);
mbedtls_md_free(&md5_ctx);
}
/* 将16进制数转换为字符串 */
void hex2str(uint8_t *input, uint32_t input_len, char *output)
{
char *upper = "0123456789ABCDEF";
int i = 0;
int j = 0;
for (i = 0; i< input_len; i++)
{
output[j++] = upper[(input[i]>>4)&0x0F];
output[j++] = upper[(input[i])&0x0F];
}
output[j] = 0;
}
void mqtt_event_callback(void *event_handler_arg,
esp_event_base_t event_base,
int32_t event_id,
void *event_data)
{
esp_mqtt_event_handle_t data = (esp_mqtt_event_handle_t)event_data;
switch (event_id)
{
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "aliot mqtt connected");
// esp_mqtt_client_subscribe_single(mqtt_handle, MQTT_TOPOC2, 1);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "aliot mqtt disconnected");
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "aliot mqtt published ack");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "aliot mqtt subcribed ack");
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "topic->%s", data->topic);
ESP_LOGI(TAG, "payload->%s", data->data);
break;
default: break;
}
}
char password_buf[33];
char *sign_hmac(char *deviceScrect, char *content)
{
unsigned char password_hex[16];
cal_md5(deviceScrect, content, password_hex);//计算出16进制的密码
hex2str(password_hex, 16, password_buf);//将16进制数转换为字符串
return password_buf;
}
/* 启动阿里云IoT连接 */
void mqtt_start(void)
{
esp_mqtt_client_config_t mqtt_cfg = {0};
mqtt_cfg.broker.address.uri = ALIOT_MQTT_URL;
mqtt_cfg.broker.address.port = 8883;//注意:由于使用了阿里云平台的自签名证书,端口号需改成8883
//mqttClientId: clientId+"|securemode=3,signmethod=hmacsha1,timestamp=132323232|"
char client_id[128];
snprintf(client_id, sizeof(client_id),
"%s|securemode=2,signmethod=hmacmd5|",// 选择TLS直连,md5加密
get_clientid());
mqtt_cfg.credentials.client_id = client_id;
//mqttUsername: deviceName+"&"+productKey
char user_name[128];
snprintf(user_name, sizeof(user_name),"%s&%s", ALIOT_DEVICENAME, ALIOT_PRODUCTKEY);
mqtt_cfg.credentials.username = user_name;
//mqttPassword:sign_hmac(deviceSecret, content)
char sign_content[128];
snprintf(sign_content, sizeof(sign_content), "clientId%sdeviceName%sproductKey%s",
get_clientid(), ALIOT_DEVICENAME, ALIOT_PRODUCTKEY);//获取内容
#if 0
unsigned char password_hex[16];
char password_str[33];
cal_md5(ALIOT_DEVICESECRET, sign_content, password_hex);//计算出16进制的密码
hex2str(password_hex, 16, password_str);//将16进制数转换为字符串
mqtt_cfg.credentials.authentication.password = password_str;
#else
char *password_pStr = sign_hmac(ALIOT_DEVICESECRET, sign_content);
mqtt_cfg.credentials.authentication.password = password_pStr;
#endif
//TLS证书
mqtt_cfg.broker.verification.certificate = ali_iot_ca;
//发起MQTT连接
mqtt_handle = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_register_event(mqtt_handle, ESP_EVENT_ANY_ID, mqtt_event_callback, NULL);//注册事件响应回调函数
esp_mqtt_client_start(mqtt_handle);
}
3.4 链接多个文件
在./main/cMakeList.txt文件中添加以下代码,将main.c、wifi.c、mqtt_aliot.c链接起来:
idf_component_register(SRCS "main.c" "wifi.c" "mqtt_aliot.c"
INCLUDE_DIRS "")
4.验证功能
设备运行前:
编译-->烧录-->打开串口监视-->打开WiFi热点:
5.注意事项
- 因为使用了阿里云物联网平台TLS自签名证书,因此端口号要用8883替换1883;
- MQTT域名需加上"mqtts://"前缀(因为是加密的,所以mqtt后必须加一个s);
- 要在menuconfig中使能Enable RIPEMD-160 hash algorithm这个哈希算法,否则无法识别阿里云物联网平台自签名证书;
6.参考文档
使用TLS加密设备和物联网平台的MQTT通信_物联网平台(IoT)-阿里云帮助中心