极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 16099|回复: 0

【ESP8266 Non-OS SDK开发探坑之七】-简单的TCP状态上报客户端

[复制链接]
发表于 2018-9-11 23:31:29 | 显示全部楼层 |阅读模式

【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】

原博客格式友好,欢迎来访
http://www.straka.cn/blog/esp82666-7-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的时候就执行该回调。

回调函数:

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解析回调:

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状态,如果还未成功就重试。

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定时器,用来定时发送设备状态、传感器数据等。发送消息到任务队列排队发送。

void ICACHE_FLASH_ATTR
StationTimerCB(){
        system_os_post(TCPCOMM_TASK_PRIO, TSIG_REPORT,0x00);
}
而在任务队列中将消息收集好发送:

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_NONOS_SDK-2.2.1-WebServer

https://github.com/atp798/BlogStraka/


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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-25 14:21 , Processed in 0.041504 second(s), 18 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表