ESP8266 mqtt OS2.0調試源碼
mqtt內部原理,請自行查閱相關資料。至於爲什麼不想說這些東西,請查看下圖1。
我的代碼實在官網Demo下,發現一些問題,經過修改完善的。下面直接看代碼。
這個代碼就是一個任務,包括初始化以及發佈消息。我是使用了一個隊裏,有消息來了,就把消息發送出去。其中MQTT_BROKER是服務器IP地址。
typedef struct esp_mqtt_msg_type {
long unsigned int len;
char allData[1460];
} xMessage;
xMessage pMsg_temp;
static void mqtt_client_thread(void* pvParameters)
{
vTaskSuspend(MQTTSubscribe_Monitor_handle);
printf("mqtt client thread starts\n");
// MQTTClient mqtt_client;
Network network;
unsigned char sendbuf[2048], readbuf[2048] = {0};
int rc = 0, count = 0;
MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;
pvParameters = 0;
NetworkInit(&network);
MQTTClientInit(&mqtt_client, &network, 30000, sendbuf, sizeof(sendbuf), readbuf, sizeof(readbuf));
for(;;){
while (wifi_station_get_connect_status() != STATION_GOT_IP) {
vTaskDelay(1000 / portTICK_RATE_MS);
}
char* address = MQTT_BROKER;
connectData.MQTTVersion = 3;
connectData.clientID.cstring = "admin";
connectData.username.cstring = "admin";
connectData.password.cstring = "public";
connectData.keepAliveInterval = 40;
connectData.cleansession = true;
//底層的TCP開始連接
if ((rc = NetworkConnect(&network, address, MQTT_PORT)) != 0) {
printf("Return code from network connect is %d\n", rc);
}
#if defined(MQTT_TASK)
if ((rc = MQTTStartTask(&mqtt_client)) != pdPASS) {
printf("Return code from start tasks is %d\n", rc);
} else {
printf("Use MQTTStartTask\n");
}
#endif
//連接MQTT服務器
if ((rc = MQTTConnect(&mqtt_client, &connectData)) != 0) {
printf("Return code from MQTT connect is %d\n", rc);
} else {
printf("MQTT Connected\n");
}
vTaskResume(MQTTSubscribe_Monitor_handle);
xQueueReset(xQueue_mqtt_pb_handle);
while (1) {
pMsg_Data_Typedef pMsg;
xQueueReceive(xQueue_mqtt_pb_handle, &pMsg, portMAX_DELAY);
pMsg_temp.len=pMsg.len;
memcpy(pMsg_temp.allData,pMsg.addr,pMsg.len);
MQTTMessage message;
message.qos = QOS2;
message.retained = 0;
message.payload = pMsg_temp.allData;
message.payloadlen =(long unsigned int)pMsg_temp.len;
rc = MQTTPublish(&mqtt_client, "ESP8266/sample/pub", &message);
printf("%d ",pMsg_temp.len);
printf("%d\r\n",rc);
if(rc==SUCCESS){
uint8_t CMD_Buf[]={0x43,0x4F,0x44,0x45,0x2E,0x01,0x00};
server_recv_handler(CMD_Buf,7);
}
if (rc != 0) {
break;
}
}
network.disconnect(&network);
}
printf("mqtt_client_thread going to be deleted\n");
vTaskDelete(NULL);
return;
}
這個是訂閱註冊回調函數
static void MessageArrived(MessageData* data)
{
printf("Message arrived payload: %s\r\n", data->message->payload);
printf("Message arrived payloadlen: %d\r\n", data->message->payloadlen);
xRingbufferSend(spi_slave_tx_ring_buf, (void *) data->message->payload,data->message->payloadlen, portMAX_DELAY);
}
大家發現沒有,我上面還確實接收訂閱的代碼。其實就是MQTTSubscribe這個函數。在Demo裏,它是直接放在上面任務初始化裏。我後面調試發現,得每隔一段時間去調用這個函數才能接收到數據。如果只是初始化一次,回調函數是用不了的。然後我根據這個情況,重新定義了一個監視任務。
static void MQTTSubscribe_Monitor(void* pvParameters){
int rc = 0;
for(;;)
{
MQTTSubscribe(&mqtt_client, "ESP8266/sample/sub", QOS2, MessageArrived);
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
這樣的話,每隔1S就會調用一次。經過調試就可以用啦。
我的服務器是搭建在阿里雲上的,這個可以提供一個搭建服務器的包。裏面包括了安裝步驟。需要的自行下載。
服務器搭建安裝包