#include "FreeRTOS.h" #include "task.h" #include "queue.h" #include #include #include #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); }