ESP8266 Non-OS SDK開發探坑之七-簡單的TCP狀態上報客戶端

Starting with ESP8266 — Light a LED

Starting with ESP8266 (2)–Touch to control relay status-circuit design & electronic components selection

Starting with ESP8266(3) — Touch to control Relay-Programming & PCB design

Starting with ESP8266(4)–User parameters securely save & load on flash

Starting with ESP8266(5)–Simple HTTP configure server

Starting with ESP8266(6)–Simple TCP command server

Starting with ESP8266(7)–Simple TCP report client

繼TCP Server之後,推出TCP Client,用於完成信息的上報,其實這兩個保留一個即可完成幾乎全部功能,這裏既然是造輪子,既然是探坑,就索性一併實現了。

至於只保留一個,如果是TCP Server,可以配備查詢命令,即可返回所需要的傳感器狀態和數據。

而如果是TCP Client,在定時上報的時候服務端可以順帶返回指令,不過缺點是指令有延遲,必須等ESP8266上報的時候才能進行指令控制,實時性靠上報的頻率決定。

TCP Client比TCP Server複雜點,需要遠程服務器的鏈接信息,比如IP和Port,這裏爲了能支持的更泛一些,我也加入了DNS支持的方法,所以就顯的繁瑣了。首先,TCP Client連接的遠程服務器信息需要提前配置,可以 用宏進行固定燒寫,可以用上一篇的TCP Server進行配置,當然也可以用上上篇節的Web server 進行配置。這裏採用web server 的serverconfig頁面進行配置並保存到flash(參看【Starting with ESP8266(4)–User parameters securely save & load on flash】)。

要開啓TCP Client,首先要連上wifi,否則client無法連接遠程服務器,所以開啓tcp client的命令需要在wifi連上的時候進行。

我把和wifi相關的部分行爲放在了WifiManager.c文件中。主要是wifi AP、Station參數配置模式切換,並開啓定時器對wifi狀態輪詢以便進行程序狀態控制。wifi的斷線重連 SDK有提供api

通過wifi_station_get_connect_status();函數查詢狀態,可以得到:

STATION_IDLE

STATION_CONNECTING

STATION_WRONG_PASSWORD

STATION_NO_AP_FOUND

STATION_CONNECT_FAIL

STATION_GOT_IP

這裏主要是在STATION_GOT_IP狀態下進行處理,自定義了一個回調,如果配置了該回調函數,那麼當連上wifi的時候就執行該回調。

回調函數:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

void ICACHE_FLASH_ATTR

WifiStaConnCB(){

if(!TCPServOn){

TCPServInit(TCP_SERV_PORT);

}

if(!TCPClientOn){

if(stFlashProtParam.Domain){

struct ip_info stationIP;

wifi_get_ip_info(STATION_IF,&stationIP);

memcpy(tcpDNSTmp.local_ip,&stationIP.ip.addr,4);

 

connDNSTmp.type = ESPCONN_TCP;

connDNSTmp.state = ESPCONN_NONE;

connDNSTmp.proto.tcp = &tcpDNSTmp;

 

    espconn_gethostbyname(&connDNSTmp,stFlashProtParam.RemoteAddr.Domain , &ipDNS, DNSFoundCB);

 

    os_timer_disarm(&tmDNS);

    os_timer_setfn(&tmDNS, (os_timer_func_t *)DNSRetryTimerCB, &connDNSTmp);

    os_timer_arm(&tmDNS, 5000, 0);

}else{

TCPClientInit(stFlashProtParam.RemoteAddr.IP.addr, stFlashProtParam.RemotePort);

StationTimerInit();

}

}

}

這裏面判斷了如果TCPServer或者TCP Client沒開啓就開啓,其中TCP Client判斷如果遠端服務器是域名信息,則啓動dns和dns狀態控制定時器。

dns解析回調:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

LOCAL void ICACHE_FLASH_ATTR

DNSFoundCB(const char *name, ip_addr_t *ipAddr, void *arg)

{

    struct espconn *pEspConn = (struct espconn *)arg;

    if (ipAddr == NULL) {

     DNSRetryCtn++;

        TRACE("domain dns not found\r\n");

        return;

    }

 

    DNSFound = true;

    TRACE("domain dns found "IPSTR"\n",IP2STR(ipAddr));

TCPClientInit(ipAddr->addr, stFlashProtParam.RemotePort);

StationTimerInit();

}

回調裏判斷是否成功獲取到IP,如果是,則開啓TCP Client,否則自增重試次數,在定時器回調裏判斷DNS狀態,如果還未成功就重試。

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

LOCAL void ICACHE_FLASH_ATTR

DNSRetryTimerCB(void *arg)

{

    struct espconn *pEspConn = arg;

    TRACE("DNS retry\n");

    if(DNSFound){

    os_timer_disarm(&tmDNS);

     return;

    }

    espconn_gethostbyname(pEspConn, (char *)stFlashProtParam.RemoteAddr.Domain, &ipDNS, DNSFoundCB);

if(DNSRetryCtn >= MAX_DNS_RETRY ){

system_os_post(TCPCOMM_TASK_PRIO, TSIG_DNS_FAILED, 0x00);

DNSRetryCtn = 0;

    os_timer_disarm(&tmDNS);

}else{

os_timer_arm(&tmDNS, 5000, 0);

}

}

當TCP Client成功連接服務器後,開啓StationTimer定時器,用來定時發送設備狀態、傳感器數據等。發送消息到任務隊列排隊發送。

1

2

3

4

void ICACHE_FLASH_ATTR

StationTimerCB(){

system_os_post(TCPCOMM_TASK_PRIO, TSIG_REPORT,0x00);

}

而在任務隊列中將消息收集好發送:

1

2

3

4

5

6

7

case TSIG_REPORT:

if(!TCPClientOn) return;

LOCAL char szSendBuf[64];

os_memset(szSendBuf,0,sizeof(szSendBuf));

os_sprintf(szSendBuf,"{\"relay\":\"%s\"}",RelayStatus?"off":"on");

TCPResponse(&connClient,szSendBuf,(uint16)os_strlen(szSendBuf));

break;

相比前文的兩個server,client的收發數據回調都不怎麼做什麼。如果需要服務端的確認消息,可以在接收回調裏處理。

此外,由於web配置的時候講過tcp client 連接服務器支持服務器域名格式,那麼如果服務器是部署在局域網內,那麼爲了更方便進行配置部署,在局域網內部署一個DNS服務器,我用的dnsmasq,然後將路由器的DNS解析指向該服務器即可,我先是把cubieboard 上部署了dnsmasq,解析速度只需要不到1ms,但突然某天cubieboard硬件故障無法啓動了,只好把路由器刷了老毛子固件,然後直接用路由器上的dnsmasq, 好在都支持泛域名解析,但是解析速度降到5ms左右了。

如上圖配置即可完成泛域名解析。

代碼見:

原博客:

http://www.straka.cn/blog/esp82666-7-tcp-report-client/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章