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

ESP8266 Non-OS SDK开发探坑之七-简单的TCP状态上报客户端_第1张图片

通过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左右了。ESP8266 Non-OS SDK开发探坑之七-简单的TCP状态上报客户端_第2张图片

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

代码见:

原博客:

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

你可能感兴趣的:(diy,hardware,ESP8266)