5.12更新:
需要注意調用cJSON_Print函數將JSON體轉化為字符串時,會開辟內存,轉化後使用完畢後需要調用cJSON_free函數將內存釋放掉,否則會導致內存泄漏。一旦內存泄漏會導致系統宕機。
本項目使用了W801以一機一密的方式連接至阿裡雲物聯網平臺,定時發送數據並實現了反向控制。
因為使用阿裡雲物聯網平臺,因此需要提前創建好一個設備,這個網上的示例和阿裡雲自己的文檔已經十分完整,因此不多贅述,可以自行查閱。創建完設備的MQTT鏈接參數是用來進行鏈接的關鍵,如下圖所示。
概述:SDK中提供的MQTT鏈接示例基本是可用的,但是連接阿裡雲時需要做如下修改。
【1】修改MQTT鏈接參數,同時要添加Username以及password的宏定義,訂閱和發布的topic根據自己的設備來添加
【2】修改MQTT的client,username等的數組長度,SDK中的數據範圍太小,而阿裡雲的鏈接參數由於經過加密因此比較長無法滿足要求,需要對以下幾個位置進行修改。
【3】修改原MQTTdemo裡面的mqtt_demo_init函數,原函數沒有賬戶密碼登錄的步驟,但是提供了相應函數,因此需要進行補充。
【1】概述:在原demo上修改,添加了一個硬件定時器,定時5s後在中斷服務函數,向隊列裡添加一個MQTT_MSG_PUBLISH_CB標志,主循環讀取到這個標志後會進行mqtt消息發送,這邊還涉及到一個數據處理成為JSON格式,我這裡只發送一個溫度信息,格式為{"temperature":"20"},用的就是cJSON庫,這個參考下網上其他文章即可。
【2】代碼如下:
//mqtt消息發送函數
static int mqtt_msg_pub(void)
{
char *temperature_msg;
temperature_msg = datatoJSON(temp_label, temperature);
mqtt_publish(&mqtt_demo_mqtt_broker, (const char *)MQTT_DEMO_RX_PUB_TOPIC, (const char *)temperature_msg, strlen(temperature_msg), 0);
tls_os_queue_send(mqtt_demo_task_queue, (void *)MQTT_DEMO_CMD_LOOP, 0);
cJSON_free(temperature_msg);
return 0;
}
//demo中原來的主循環
static void mqtt_demo_task(void *p)
{
int ret;
void *msg;
struct tls_ethif *ether_if = tls_netif_get_ethif();
if (ether_if->status)
{
wm_printf("sta ip: %v\n", ether_if->ip_addr.addr);
tls_os_queue_send(mqtt_demo_task_queue, (void *)MQTT_DEMO_CMD_START, 0);
}
for ( ; ; )
{
ret = tls_os_queue_receive(mqtt_demo_task_queue, (void **)&msg, 0, 0);
if (!ret)
{
switch((u32)msg)
{
case MQTT_DEMO_CMD_START:
do
{
ret = mqtt_demo_init();
if (ret)
break;
tls_os_queue_send(mqtt_demo_task_queue, (void *)MQTT_DEMO_CMD_LOOP, 0);
timer_pub();
}
while (0);
break;
case MQTT_DEMO_CMD_HEART:
//wm_printf("send heart ping\r\n");
mqtt_ping(&mqtt_demo_mqtt_broker);
break;
case MQTT_DEMO_CMD_LOOP:
mqtt_demo_loop();
break;
case MQTT_MSG_PUBLISH_CB: //添加一個新的標志,讀取到這個標志時候,進行消息發送
mqtt_msg_pub();
break;
default:
break;
}
}
}
}
//中斷函數中向隊列添加標志
static void timer_pub_irq(u8 *arg)
{
//printf("timer irq\n");
tls_os_queue_send(mqtt_demo_task_queue, (void *)MQTT_MSG_PUBLISH_CB, 0);
}
//上傳數據硬件定時器
int timer_pub(void)
{
u8 timer_id;
struct tls_timer_cfg timer_cfg;
timer_cfg.unit = TLS_TIMER_UNIT_MS;
timer_cfg.timeout = 5000;
timer_cfg.is_repeat = 1;
timer_cfg.callback = (tls_timer_irq_callback)timer_pub_irq;
timer_cfg.arg = NULL;
timer_id = tls_timer_create(&timer_cfg);
tls_timer_start(timer_id);
return WM_SUCCESS;
}
【1】阿裡雲實際上可以采用物模型進行反向控制,但是那個相對比較麻煩,這裡我采用一個比較通用的辦法,w801訂閱了一個topic接受該topic命令並解析,再進行對應操作。這一部分邏輯與我前一篇文章,藍牙反向控制相似,這裡給出鏈接可以作為參考。
w801通過藍牙更新wifi並自動重連
【2】代碼:
static int mqtt_demo_loop(void)
{
int packet_length = 0;
int counter = 0;
counter++;
packet_length = mqtt_demo_read_packet(0, 1);
if(packet_length > 0)
{
if (MQTTParseMessageType(mqtt_demo_packet_buffer) == MQTT_MSG_PUBLISH)
{
uint8_t topic[100], *msg;
uint16_t len;
len = mqtt_parse_pub_topic(mqtt_demo_packet_buffer, topic);
topic[len] = '\0'; // for printf
len = mqtt_parse_publish_msg(mqtt_demo_packet_buffer, &msg);
msg[len] = '\0'; // for printf
//wm_printf("recvd: %s >>> %s\n", topic, msg);
aliyun_cmd_excute(msg);
}
tls_os_queue_send(mqtt_demo_task_queue, (void *)MQTT_DEMO_CMD_LOOP, 0);
}
else if (packet_length == MQTT_DEMO_READ_TIMEOUT)
{
tls_os_queue_send(mqtt_demo_task_queue, (void *)MQTT_DEMO_CMD_LOOP, 0);
}
else if(packet_length == -1)
{
wm_printf("mqtt error:(%d), stop mqtt demo!\n", packet_length);
tls_os_timer_stop(mqtt_demo_heartbeat_timer);
mqtt_demo_close_socket(&mqtt_demo_mqtt_broker);
}
return 0;
}
int aliyun_cmd_excute(char *cmd)
{
//解析Json字符串
cJSON *str_json, *str_cmd;
str_json = cJSON_Parse(cmd);
if (!str_json)
{
printf("[INFO]: JSON格式錯誤: %s\r\n", cJSON_GetErrorPtr());
}
else
{
str_cmd = cJSON_GetObjectItem(str_json, "cmd");
if (str_cmd->type == cJSON_Number)
{
//printf("[INFO]: cmd: %d\r\n", str_cmd->valueint);
if (str_cmd->valueint == 1)
{
temperature++;
printf("[CMD_ALIYUN]: Temperature rise by aliyun, the current temp is %d\n",temperature);
}
else if (str_cmd->valueint == 2)
{
temperature--;
printf("[CMD_ALIYUN]: Temperature drops by aliyun, the current temp is %d\n",temperature);
}
}
}
cJSON_delete(str_json);
return WM_SUCCESS;
}
謝謝,學習了
使用後,提示MQTT_MSG_PUBLISH_CB未聲明,怎麼改?