mqtt_test.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. #include "FreeRTOS.h"
  2. #include "task.h"
  3. #include "queue.h"
  4. #include <stdint.h>
  5. #include <stdio.h>
  6. #include <netdb.h>
  7. #include "mqtt.h"
  8. #include "hmac.h"
  9. #include "string.h"
  10. /* 用户需要根据设备信息完善以下宏定义中的三元组内容 */
  11. #define PRODUCT_KEY "a1UkrNcVEav" /* 阿里云颁发的产品唯一标识,11位长度的英文数字随机组合 */
  12. #define DEVICE_NAME "light1" /* 用户注册设备时生成的设备唯一编号,支持系统自动生成,也可支持用户添加自定义编号,产品维度内唯一 */
  13. #define DEVICE_SECRET "9052e173e9991402cdf1c9685f0c7782" /* 设备密钥,与DeviceName成对出现,可用于一机一密的认证方案 */
  14. /* 以下参数的宏定义固定,不需要修改,只修改上方的参数即可 */
  15. #define HOST_NAME PRODUCT_KEY".iot-as-mqtt.cn-shanghai.aliyuncs.com" /* 阿里云域名 */
  16. #define HOST_PORT 1883 /* 阿里云域名端口,固定1883 */
  17. #define CONTENT "clientId"DEVICE_NAME"deviceName"DEVICE_NAME"productKey"PRODUCT_KEY"timestamp789" /* 计算登录密码用 */
  18. #define CLIENT_ID DEVICE_NAME"|securemode=3,signmethod=hmacsha1,timestamp=789|" /* 客户端ID */
  19. #define USER_NAME DEVICE_NAME"&"PRODUCT_KEY /* 客户端用户名 */
  20. #define DEVICE_PUBLISH "/"PRODUCT_KEY"/"DEVICE_NAME"/user/light_state" /* 发布 */
  21. #define DEVICE_SUBSCRIBE "/"PRODUCT_KEY"/"DEVICE_NAME"/user/light_ctrl" /* 订阅 */
  22. static ip_addr_t g_mqtt_ip;
  23. static mqtt_client_t* g_mqtt_client;
  24. unsigned char g_payload_out[200];
  25. static int g_publish_flag = 0;/* 发布成功标志位 */
  26. void lwip_ali_get_password(const char *device_secret, const char *content, char *password);
  27. static char password[300];
  28. static int light_state = 0;
  29. /**
  30. * @brief mqtt进入数据回调函数
  31. * @param arg:传入的参数
  32. * @param data:数据
  33. * @param len:数据大小
  34. * @param flags:标志
  35. * @retval 无
  36. */
  37. static void
  38. mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags)
  39. {
  40. int i;
  41. const struct mqtt_connect_client_info_t* client_info = (const struct mqtt_connect_client_info_t*)arg;
  42. LWIP_UNUSED_ARG(data);
  43. if (!client_info)
  44. return;
  45. printf("\r\nMQTT client \"%s\" data cb: len %d, flags %d\n", client_info->client_id,(int)len, (int)flags);
  46. if (flags & MQTT_DATA_FLAG_LAST)
  47. {
  48. /* 从这里可以接收阿里云发布的数据 */
  49. printf("[mqtt rx] len:%d\r\n", len);
  50. printf("[mqtt rx] data:\r\n");
  51. if (data) {
  52. if (data[0] == '1') {
  53. light_state = 1;
  54. } else if (data[0] == '0') {
  55. light_state = 0;
  56. }
  57. for (i = 0; i < len; i++) {
  58. printf("%c", data[i]);
  59. }
  60. printf("\r\n");
  61. }
  62. }
  63. }
  64. /**
  65. * @brief mqtt进入发布回调函数
  66. * @param arg:传入的参数
  67. * @param topic:主题
  68. * @param tot_len:主题大小
  69. * @retval 无
  70. */
  71. static void
  72. mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len)
  73. {
  74. const struct mqtt_connect_client_info_t* client_info = (const struct mqtt_connect_client_info_t*)arg;
  75. if (!client_info)
  76. return;
  77. printf("\r\nMQTT client \"%s\" publish cb: topic %s, len %d\r\n", client_info->client_id,
  78. topic, (int)tot_len);
  79. }
  80. /**
  81. * @brief mqtt发布回调函数
  82. * @param arg:传入的参数
  83. * @param err:错误值
  84. * @retval 无
  85. */
  86. static void
  87. mqtt_publish_request_cb(void *arg, err_t err)
  88. {
  89. printf("publish success\r\n");
  90. }
  91. /**
  92. * @brief mqtt订阅响应回调函数
  93. * @param arg:传入的参数
  94. * @param err:错误值
  95. * @retval 无
  96. */
  97. static void
  98. mqtt_request_cb(void *arg, err_t err)
  99. {
  100. const struct mqtt_connect_client_info_t* client_info = (const struct mqtt_connect_client_info_t*)arg;
  101. g_publish_flag = 1;
  102. printf("\r\nMQTT client \"%s\" request cb: err %d\r\n", client_info->client_id, (int)err);
  103. }
  104. /**
  105. * @brief mqtt连接回调函数
  106. * @param client:客户端控制块
  107. * @param arg:传入的参数
  108. * @param status:连接状态
  109. * @retval 无
  110. */
  111. static void
  112. mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status)
  113. {
  114. err_t err;
  115. const struct mqtt_connect_client_info_t* client_info = (const struct mqtt_connect_client_info_t*)arg;
  116. LWIP_UNUSED_ARG(client);
  117. printf("\r\nMQTT client \"%s\" connection cb: status %d\r\n", client_info->client_id, (int)status);
  118. /* 判断是否连接 */
  119. if (status == MQTT_CONNECT_ACCEPTED)
  120. {
  121. /* 判断是否连接 */
  122. if (mqtt_client_is_connected(client))
  123. {
  124. printf("Successfully connected to the server!\n");
  125. /* 设置传入发布请求的回调 */
  126. mqtt_set_inpub_callback(g_mqtt_client,
  127. mqtt_incoming_publish_cb,
  128. mqtt_incoming_data_cb,
  129. arg);
  130. /* 订阅操作,并设置订阅响应会回调函数mqtt_sub_request_cb */
  131. err = mqtt_subscribe(client, DEVICE_SUBSCRIBE, 1, mqtt_request_cb, arg);
  132. if(err == ERR_OK)
  133. {
  134. printf("mqtt_subscribe return: %d\n", err);
  135. }
  136. }
  137. }
  138. else/* 连接失败 */
  139. {
  140. printf("mqtt_connection_cb: Disconnected, reason: %d\n", status);
  141. }
  142. }
  143. /**
  144. * @brief mqtt测试
  145. * @param 无
  146. * @retval 无
  147. */
  148. void mqtt_test(void)
  149. {
  150. struct hostent *server;
  151. static struct mqtt_connect_client_info_t mqtt_client_info;
  152. int last_light_state = light_state;
  153. server = gethostbyname((char *)HOST_NAME); /* 服务器地址解析 */
  154. if (!server) {
  155. printf("dns fail!\n");
  156. return;
  157. }
  158. memcpy(&g_mqtt_ip,server->h_addr,server->h_length); /* 把解析好的地址存放在mqtt_ip变量当中 */
  159. /* 为密码申请内存 */
  160. lwip_ali_get_password(DEVICE_SECRET, CONTENT, password); /* 通过hmac_sha1算法得到password */
  161. /* 设置一个空的客户端信息结构 */
  162. memset(&mqtt_client_info, 0, sizeof(mqtt_client_info));
  163. /* 设置客户端的信息量 */
  164. mqtt_client_info.client_id = (char *)CLIENT_ID; /* 设备名称 */
  165. mqtt_client_info.client_user = (char *)USER_NAME; /* 产品ID */
  166. mqtt_client_info.client_pass = (char *)password; /* 计算出来的密码 */
  167. mqtt_client_info.keep_alive = 100; /* 保活时间 */
  168. mqtt_client_info.will_msg = NULL;
  169. mqtt_client_info.will_qos = NULL;
  170. mqtt_client_info.will_retain = 0;
  171. mqtt_client_info.will_topic = 0;
  172. /* 创建MQTT客户端控制块 */
  173. g_mqtt_client = mqtt_client_new();
  174. /* 连接服务器 */
  175. mqtt_client_connect(g_mqtt_client, /* 服务器控制块 */
  176. &g_mqtt_ip, MQTT_PORT,/* 服务器IP与端口号 */
  177. mqtt_connection_cb, LWIP_CONST_CAST(void*, &mqtt_client_info),/* 设置服务器连接回调函数 */
  178. &mqtt_client_info); /* MQTT连接信息 */
  179. while(1)
  180. {
  181. if (g_publish_flag == 1) {
  182. if (light_state)
  183. mqtt_publish(g_mqtt_client,DEVICE_PUBLISH, "1",1,1,0,mqtt_publish_request_cb,NULL);
  184. else
  185. mqtt_publish(g_mqtt_client,DEVICE_PUBLISH, "0",1,1,0,mqtt_publish_request_cb,NULL);
  186. last_light_state = light_state;
  187. }
  188. vTaskDelay(1000);
  189. }
  190. }
  191. /**
  192. * @brief 将16进制数转化为字符串
  193. * @param pbSrc - 输入16进制数的起始地址
  194. * @param nLen - 16进制数的字节数
  195. * @param pbDest - 存放目标字符串
  196. * @retval 无
  197. */
  198. static void lwip_ali_hextostr(uint8_t *pbDest, uint8_t *pbSrc, int nLen)
  199. {
  200. char ddl, ddh;
  201. int i;
  202. for (i = 0; i < nLen; i++)
  203. {
  204. ddh = 48 + pbSrc[i] / 16;
  205. ddl = 48 + pbSrc[i] % 16;
  206. if (ddh > 57) ddh = ddh + 7;
  207. if (ddl > 57) ddl = ddl + 7;
  208. pbDest[i * 2] = ddh;
  209. pbDest[i * 2 + 1] = ddl;
  210. }
  211. pbDest[nLen * 2] = '\0';
  212. }
  213. /**
  214. * @brief 通过hmac_sha1算法获取password
  215. * @param device_secret---设备的密钥
  216. * @param content --- 登录密码
  217. * @param password---返回的密码值
  218. * @retval 无
  219. */
  220. static void lwip_ali_get_password(const char *device_secret, const char *content, char *password)
  221. {
  222. char buf[256] = {0};
  223. int len = sizeof(buf);
  224. hmac_sha1((uint8_t *)device_secret, strlen(device_secret), (uint8_t *)content, strlen(content), (uint8_t *)buf, (unsigned int *)&len);
  225. lwip_ali_hextostr((uint8_t *)password, (uint8_t *)buf, len);
  226. }