| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- #include "FreeRTOS.h"
- #include "task.h"
- #include "queue.h"
- #include <stdint.h>
- #include <stdio.h>
- #include <netdb.h>
- #include "mqtt.h"
- #include "hmac.h"
- #include "string.h"
- /* 用户需要根据设备信息完善以下宏定义中的三元组内容 */
- #define PRODUCT_KEY "a1UkrNcVEav" /* 阿里云颁发的产品唯一标识,11位长度的英文数字随机组合 */
- #define DEVICE_NAME "light1" /* 用户注册设备时生成的设备唯一编号,支持系统自动生成,也可支持用户添加自定义编号,产品维度内唯一 */
- #define DEVICE_SECRET "9052e173e9991402cdf1c9685f0c7782" /* 设备密钥,与DeviceName成对出现,可用于一机一密的认证方案 */
- /* 以下参数的宏定义固定,不需要修改,只修改上方的参数即可 */
- #define HOST_NAME PRODUCT_KEY".iot-as-mqtt.cn-shanghai.aliyuncs.com" /* 阿里云域名 */
- #define HOST_PORT 1883 /* 阿里云域名端口,固定1883 */
- #define CONTENT "clientId"DEVICE_NAME"deviceName"DEVICE_NAME"productKey"PRODUCT_KEY"timestamp789" /* 计算登录密码用 */
- #define CLIENT_ID DEVICE_NAME"|securemode=3,signmethod=hmacsha1,timestamp=789|" /* 客户端ID */
- #define USER_NAME DEVICE_NAME"&"PRODUCT_KEY /* 客户端用户名 */
- #define DEVICE_PUBLISH "/"PRODUCT_KEY"/"DEVICE_NAME"/user/light_state" /* 发布 */
- #define DEVICE_SUBSCRIBE "/"PRODUCT_KEY"/"DEVICE_NAME"/user/light_ctrl" /* 订阅 */
- static ip_addr_t g_mqtt_ip;
- static mqtt_client_t* g_mqtt_client;
- unsigned char g_payload_out[200];
- static int g_publish_flag = 0;/* 发布成功标志位 */
- void lwip_ali_get_password(const char *device_secret, const char *content, char *password);
- static char password[300];
- static int light_state = 0;
- /**
- * @brief mqtt进入数据回调函数
- * @param arg:传入的参数
- * @param data:数据
- * @param len:数据大小
- * @param flags:标志
- * @retval 无
- */
- static void
- mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags)
- {
- int i;
- const struct mqtt_connect_client_info_t* client_info = (const struct mqtt_connect_client_info_t*)arg;
- LWIP_UNUSED_ARG(data);
- if (!client_info)
- return;
- printf("\r\nMQTT client \"%s\" data cb: len %d, flags %d\n", client_info->client_id,(int)len, (int)flags);
-
- if (flags & MQTT_DATA_FLAG_LAST)
- {
- /* 从这里可以接收阿里云发布的数据 */
- printf("[mqtt rx] len:%d\r\n", len);
- printf("[mqtt rx] data:\r\n");
- if (data) {
- if (data[0] == '1') {
- light_state = 1;
- } else if (data[0] == '0') {
- light_state = 0;
- }
- for (i = 0; i < len; i++) {
- printf("%c", data[i]);
- }
- printf("\r\n");
- }
- }
- }
- /**
- * @brief mqtt进入发布回调函数
- * @param arg:传入的参数
- * @param topic:主题
- * @param tot_len:主题大小
- * @retval 无
- */
- static void
- mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len)
- {
- const struct mqtt_connect_client_info_t* client_info = (const struct mqtt_connect_client_info_t*)arg;
- if (!client_info)
- return;
- printf("\r\nMQTT client \"%s\" publish cb: topic %s, len %d\r\n", client_info->client_id,
- topic, (int)tot_len);
- }
- /**
- * @brief mqtt发布回调函数
- * @param arg:传入的参数
- * @param err:错误值
- * @retval 无
- */
- static void
- mqtt_publish_request_cb(void *arg, err_t err)
- {
- printf("publish success\r\n");
- }
- /**
- * @brief mqtt订阅响应回调函数
- * @param arg:传入的参数
- * @param err:错误值
- * @retval 无
- */
- static void
- mqtt_request_cb(void *arg, err_t err)
- {
- const struct mqtt_connect_client_info_t* client_info = (const struct mqtt_connect_client_info_t*)arg;
-
- g_publish_flag = 1;
- printf("\r\nMQTT client \"%s\" request cb: err %d\r\n", client_info->client_id, (int)err);
- }
- /**
- * @brief mqtt连接回调函数
- * @param client:客户端控制块
- * @param arg:传入的参数
- * @param status:连接状态
- * @retval 无
- */
- static void
- mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
- {
- err_t err;
-
- const struct mqtt_connect_client_info_t* client_info = (const struct mqtt_connect_client_info_t*)arg;
-
- LWIP_UNUSED_ARG(client);
- printf("\r\nMQTT client \"%s\" connection cb: status %d\r\n", client_info->client_id, (int)status);
- /* 判断是否连接 */
- if (status == MQTT_CONNECT_ACCEPTED)
- {
- /* 判断是否连接 */
- if (mqtt_client_is_connected(client))
- {
- printf("Successfully connected to the server!\n");
- /* 设置传入发布请求的回调 */
- mqtt_set_inpub_callback(g_mqtt_client,
- mqtt_incoming_publish_cb,
- mqtt_incoming_data_cb,
- arg);
-
- /* 订阅操作,并设置订阅响应会回调函数mqtt_sub_request_cb */
- err = mqtt_subscribe(client, DEVICE_SUBSCRIBE, 1, mqtt_request_cb, arg);
-
- if(err == ERR_OK)
- {
- printf("mqtt_subscribe return: %d\n", err);
- }
- }
- }
- else/* 连接失败 */
- {
- printf("mqtt_connection_cb: Disconnected, reason: %d\n", status);
- }
- }
- /**
- * @brief mqtt测试
- * @param 无
- * @retval 无
- */
- void mqtt_test(void)
- {
- struct hostent *server;
- static struct mqtt_connect_client_info_t mqtt_client_info;
- int last_light_state = light_state;
-
-
- server = gethostbyname((char *)HOST_NAME); /* 服务器地址解析 */
- if (!server) {
- printf("dns fail!\n");
- return;
- }
- memcpy(&g_mqtt_ip,server->h_addr,server->h_length); /* 把解析好的地址存放在mqtt_ip变量当中 */
-
- /* 为密码申请内存 */
- lwip_ali_get_password(DEVICE_SECRET, CONTENT, password); /* 通过hmac_sha1算法得到password */
-
-
- /* 设置一个空的客户端信息结构 */
- memset(&mqtt_client_info, 0, sizeof(mqtt_client_info));
-
- /* 设置客户端的信息量 */
- mqtt_client_info.client_id = (char *)CLIENT_ID; /* 设备名称 */
- mqtt_client_info.client_user = (char *)USER_NAME; /* 产品ID */
- mqtt_client_info.client_pass = (char *)password; /* 计算出来的密码 */
- mqtt_client_info.keep_alive = 100; /* 保活时间 */
- mqtt_client_info.will_msg = NULL;
- mqtt_client_info.will_qos = NULL;
- mqtt_client_info.will_retain = 0;
- mqtt_client_info.will_topic = 0;
-
- /* 创建MQTT客户端控制块 */
- g_mqtt_client = mqtt_client_new();
-
- /* 连接服务器 */
- mqtt_client_connect(g_mqtt_client, /* 服务器控制块 */
- &g_mqtt_ip, MQTT_PORT,/* 服务器IP与端口号 */
- mqtt_connection_cb, LWIP_CONST_CAST(void*, &mqtt_client_info),/* 设置服务器连接回调函数 */
- &mqtt_client_info); /* MQTT连接信息 */
- while(1)
- {
- if (g_publish_flag == 1) {
- if (light_state)
- mqtt_publish(g_mqtt_client,DEVICE_PUBLISH, "1",1,1,0,mqtt_publish_request_cb,NULL);
- else
- mqtt_publish(g_mqtt_client,DEVICE_PUBLISH, "0",1,1,0,mqtt_publish_request_cb,NULL);
- last_light_state = light_state;
- }
- vTaskDelay(1000);
- }
- }
- /**
- * @brief 将16进制数转化为字符串
- * @param pbSrc - 输入16进制数的起始地址
- * @param nLen - 16进制数的字节数
- * @param pbDest - 存放目标字符串
- * @retval 无
- */
- static void lwip_ali_hextostr(uint8_t *pbDest, uint8_t *pbSrc, int nLen)
- {
- char ddl, ddh;
- int i;
- for (i = 0; i < nLen; i++)
- {
- ddh = 48 + pbSrc[i] / 16;
- ddl = 48 + pbSrc[i] % 16;
- if (ddh > 57) ddh = ddh + 7;
- if (ddl > 57) ddl = ddl + 7;
- pbDest[i * 2] = ddh;
- pbDest[i * 2 + 1] = ddl;
- }
- pbDest[nLen * 2] = '\0';
- }
- /**
- * @brief 通过hmac_sha1算法获取password
- * @param device_secret---设备的密钥
- * @param content --- 登录密码
- * @param password---返回的密码值
- * @retval 无
- */
- static void lwip_ali_get_password(const char *device_secret, const char *content, char *password)
- {
- char buf[256] = {0};
- int len = sizeof(buf);
- hmac_sha1((uint8_t *)device_secret, strlen(device_secret), (uint8_t *)content, strlen(content), (uint8_t *)buf, (unsigned int *)&len);
- lwip_ali_hextostr((uint8_t *)password, (uint8_t *)buf, len);
- }
|