手机app+esp8266控制小区大门门锁,实现远程开门

        近日笔者自己动手修理自家的门铃时,发现只要接通开门的电源线,就可以打开楼宇的大门了,突发奇想:在门铃引出线加装继电器就可以用esp8266连上互联,实现远程开门了。(我家门铃比较老旧,不知其他牌子门铃是否也是可以这样操作,知道的朋友留言告诉一下)。

具体要实现的功能:通过手机app操作实现开门功能。实现原理:esp8266连接服务器,并与之交互数据,手机app向服务器发送开锁指令,服务器转发指令到esp8266,esp8266通过gpio发送高电平给继电器,接通开门电源线,实现开门。本文只从程序开发方面去说明开发的过程。更多的硬件方面的说明请看相关文档。

需要的设备清单:

继电器:信号线连接esp8266的gpio2,当高电平是继电器断开,门锁关状态,开锁时将gpio2置为低电平2秒钟,即可实现开锁.

esp8266

家庭wifi

 

立即上源码

esp8266部分,使用udp与服务器通信:(在ESP8266_NONOS_SDK-2.1.0-18上编译通过)

#include "user_interface.h"
#include "espconn.h"
#include "gpio.h"
#include "eagle_soc.h"
#include "osapi.h"    //os_printf所需要的头文件

ETSTimer my_timer,act_timer,low_timer;
struct espconn conn;
esp_udp user_udp;
ip_addr_t esp_server_ip;
void ICACHE_FLASH_ATTR init_cb(void);
void ICACHE_FLASH_ATTR espconn_cli_timer_cb(void *timer_arg);
void ICACHE_FLASH_ATTR act_timer_cb(void *timer_arg);
void ICACHE_FLASH_ATTR client_connect();
void ICACHE_FLASH_ATTR act_timer_cb(void *timer_arg);
void ICACHE_FLASH_ATTR ret_back_cb(void *timer_arg);
void ICACHE_FLASH_ATTR espconn_recv_data_cb(void *arg,char *pdata,unsigned short len);
void ICACHE_FLASH_ATTR espconn_sent_cb(void *arg);

static int gLoginSucess = 0;

void ICACHE_FLASH_ATTR espconn_recv_data_cb(void *arg,char *pdata,unsigned short len)
{//接收到服务发来的信息,进行相关的操作
    os_printf("espconn_recv_data_cb datalen:%d,conetnt[%s]\n",len,pdata);
    if(strncmp(pdata,"LOGIN_RESP",11) == 0)
    {
                gLoginSucess = 1;
                os_printf("login succeed\n");
                if(strcmp(pdata+11,"LOW") == 0)
                    GPIO_OUTPUT_SET(GPIO_ID_PIN(2), 0);
                else if(strcmp(pdata+11,"HEIGHT") == 0)
                    GPIO_OUTPUT_SET(GPIO_ID_PIN(2), 1);
                os_timer_disarm(&act_timer);
                os_timer_setfn(&act_timer,act_timer_cb, NULL);
                os_timer_arm(&act_timer, 60000, 1);
    }
    else if(strcmp(pdata,"ACK_RESP") == 0)
    {
        os_printf("act resp\n");
    }
    else if(strcmp(pdata,"OPEN") == 0)
    {
        os_printf("opt:OPEN\n");
        //gpio16_output_set(0);
        GPIO_OUTPUT_SET(GPIO_ID_PIN(2), 0);
        os_timer_disarm(&low_timer);
        os_timer_setfn(&low_timer,ret_back_cb, NULL);
        os_timer_arm(&low_timer, 500, 0);
    }
    else if(strcmp(pdata,"LOW")==0)
    {
        GPIO_OUTPUT_SET(GPIO_ID_PIN(2), 0);
        char szData[16] = {0};
        os_sprintf(szData,"LOW_RESP_%d",system_get_chip_id());
        espconn_sent(&conn,szData,strlen(szData));
    }
    else if(strcmp(pdata,"HEIGHT")==0)
    {
        GPIO_OUTPUT_SET(GPIO_ID_PIN(2), 1);
        char szData[20] = {0};
        os_sprintf(szData,"HEIGHT_RESP_%d",system_get_chip_id());
        espconn_sent(&conn,szData,strlen(szData));
    }
    else if(strcmp(pdata,"UPDATE")==0)
    {
        
    }
    else
    {
        os_printf("unknow command\n");
    }
}
void ICACHE_FLASH_ATTR espconn_sent_cb(void *arg)
{
    os_printf("espconn_sent_cb\n");   
}

void ICACHE_FLASH_ATTR ret_back_cb(void *timer_arg)
{
    //gpio16_output_set(1);
    GPIO_OUTPUT_SET(GPIO_ID_PIN(2), 1);
    char szData[16] = {0};
    os_sprintf(szData,"OPEN_RESP_%d",system_get_chip_id());
    espconn_sent(&conn,szData,strlen(szData));
}

void ICACHE_FLASH_ATTR act_timer_cb(void *timer_arg)
{
    os_printf("act_timer_cb\n");   
    char szData[16] = {0};
    os_sprintf(szData,"ACK_%d",system_get_chip_id());
    espconn_sent(&conn,szData,strlen(szData));
}
void ICACHE_FLASH_ATTR login_timer_cb(void *timer_arg)
{
    if(!gLoginSucess)
    {
        os_printf("login_timer_cb\n");
        char szData[16] = {0};
        os_sprintf(szData,"LOGIN_%d",system_get_chip_id());
        espconn_sent(&conn,szData,strlen(szData));
        os_timer_disarm(&my_timer);
        os_timer_setfn(&my_timer,login_timer_cb, NULL);
        os_timer_arm(&my_timer, 5000, 0);
    }
}
LOCAL void ICACHE_FLASH_ATTR
my_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
{
    struct espconn *pespconn = (struct espconn *)arg;

    if (ipaddr == NULL) 
    {
        os_printf("my_dns_found NULL\n");
        /*
        if (++device_recon_count == 5) {
            device_status = DEVICE_CONNECT_SERVER_FAIL;

            user_esp_platform_reset_mode();
        }*/

        return;
    }

    os_printf("my_dns_found %d.%d.%d.%d\n",
            *((uint8 *)&ipaddr->addr), *((uint8 *)&ipaddr->addr + 1),
            *((uint8 *)&ipaddr->addr + 2), *((uint8 *)&ipaddr->addr + 3));

    if (esp_server_ip.addr == 0 && ipaddr->addr != 0) 
    {
        esp_server_ip.addr = ipaddr->addr;
        os_memcpy(user_udp.remote_ip, &ipaddr->addr, 4);
    }
    os_timer_disarm(&my_timer);
    os_timer_setfn(&my_timer,espconn_cli_timer_cb, NULL);
    os_timer_arm(&my_timer, 10000, 0);
    
}
void ICACHE_FLASH_ATTR client_connect()
{    
    conn.type      = ESPCONN_UDP;
    conn.state     = ESPCONN_NONE;
    user_udp.remote_port = 9004;
    conn.proto.udp = &user_udp;
    espconn_regist_sentcb(&conn, espconn_sent_cb);
    espconn_regist_recvcb(&conn, espconn_recv_data_cb); 
    os_printf("begin espconn_connect\n");
    //espconn_connect(&conn);
    espconn_create(&conn);    
    char szData[16] = {0};
    os_sprintf(szData,"LOGIN_%d",system_get_chip_id());
    espconn_sent(&conn,szData,strlen(szData));
    os_timer_disarm(&my_timer);
    os_timer_setfn(&my_timer,login_timer_cb, NULL);//设置监听登陆成功的函数
    os_timer_arm(&my_timer, 10000, 0);
}
void ICACHE_FLASH_ATTR espconn_cli_timer_cb(void *timer_arg)
{//连接wifi,如果未连上wifi会不停重试
    init_cb();
}
void ICACHE_FLASH_ATTR init_cb(void)
{//初始化函数主要功能获取服务器的地址
    //struct ip_info info;
    //wifi_get_ip_info(STATION_IF,&info);
    uint8 status=wifi_station_get_connect_status();
    os_printf("wifi_station_get_connect_status:%d\n",status);
    if(status==STATION_GOT_IP)
    {
        if(esp_server_ip.addr == 0)
        {
            char *servername = "www.aomomo.net";
            espconn_gethostbyname(&conn, servername, &esp_server_ip, my_dns_found);
            os_printf("espconn_gethostbyname\n");
            os_timer_disarm(&my_timer);
            os_timer_setfn(&my_timer,espconn_cli_timer_cb, NULL);
            os_timer_arm(&my_timer, 10000, 0);
        }    
        else
            client_connect();//连上wifi后开始登陆服务器
       }
       else
       {
            os_printf("setup my_timer for espconn_cli_timer_cb\n");
            os_timer_disarm(&my_timer);
            os_timer_setfn(&my_timer,espconn_cli_timer_cb, NULL);
            os_timer_arm(&my_timer, 5000, 0);
       }
}
void ICACHE_FLASH_ATTR user_init()
{
    os_printf("2222222222222222222222222222222\n");
    uint8 opmode;
    //uart_init(115200,115200);
    wifi_set_opmode(STATION_MODE);//把esp8266设置为工作站的工作模式
    opmode = wifi_get_opmode();
    os_printf("current mode is: %d\n", opmode); 
    esp_server_ip.addr = 0;
/*
    struct ip_info info;
    IP4ADDR(&info.ip,192,168,1,111);
    IP4ADDR(&info.gw,192,168,1,1);
    IP4ADDR(&info.netmask,255,255,255,0);
    wifi_set_ip_info(STATION_IF,&info);
    */
       struct station_config stationconf;
     stationconf.bssid_set = 0;
     memset(stationconf.ssid, 0, sizeof(stationconf.ssid));
     memset(stationconf.password, 0, sizeof(stationconf.password));
     os_strncpy(stationconf.ssid, "esp8266", sizeof(stationconf.ssid));//设置wifi接入点
     os_strncpy(stationconf.password, "esp12345", sizeof(stationconf.password));//设置wifi接入点密码
    wifi_station_set_config(&stationconf);//设置
    gpio_init();
    //gpio16_output_conf();
    //gpio16_output_set(0);
    //gpio_output_set(0, BIT2, BIT2, 0);
    //PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U,FUNC_GPIO2);//
    //PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U,FUNC_GPIO16);//
    //PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO2);
    GPIO_OUTPUT_SET(GPIO_ID_PIN(2), 1);//设置gpio2为高电平,连接继电器的信号输入,此时继电器状态为断开。
    system_init_done_cb(init_cb);//初始化完成后的回调函数  
}
void ICACHE_FLASH_ATTR
user_rf_pre_init(){} 

 

服务器部分

//同时支持tcp与udp服务,9003为tcp服务,9004为udp服务,部署在linux服务器上

#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <string>
#include <list>
#include <map>
#include <sstream>
 

using namespace std;

int g_iMaxFd = 0;
int g_iServerSocketFd;
int g_iUdpFd;
fd_set g_set;

typedef struct _ConnInfo
{
    int iFd;
    struct sockaddr_in addr;
    unsigned int addrLen;
    time_t iLastTime;
} ConnInfo;

list<ConnInfo> g_servlist;
map<string,ConnInfo> g_client_info;

int CanSend(int fd,int p_iUsec);
int CanReceive(int fd,int p_iUsec);

 

void WriteLog(string str)
{
    printf("%s\n",str.c_str());
}

int main(int argc,char *argv[])
{

    g_iServerSocketFd = socket(AF_INET,SOCK_STREAM,0); 
    struct sockaddr_in cli_addr;
    unsigned int iNameLen;
    iNameLen = sizeof(cli_addr);
    int iFlags = fcntl(g_iServerSocketFd, F_GETFL, 0);
    fcntl(g_iServerSocketFd, F_SETFL, iFlags | O_NONBLOCK);
//#ifdef LINUX
    int iOpt;
    socklen_t iLen;
    iOpt = 1;
    iLen = sizeof(iOpt);
    //free the port
    setsockopt(g_iServerSocketFd, SOL_SOCKET, SO_REUSEADDR, (void *)&iOpt, iLen);
//#endif

    struct sockaddr_in serv_addr;
    memset((void *)&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(9003);
    //bind to the specify port
    if(bind(g_iServerSocketFd,(struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        WriteLog( "Server:Can't bind local address! 9003\n");
        return false;
    }
    //begin listen
    listen(g_iServerSocketFd,5);

    struct sockaddr_in  localAddr;
    g_iUdpFd =  socket(AF_INET, SOCK_DGRAM, 0);
    bzero(&localAddr, sizeof(localAddr));
    localAddr.sin_family = AF_INET;
    localAddr.sin_port = htons(9004);
    localAddr.sin_addr.s_addr = INADDR_ANY;
    iFlags = fcntl(g_iUdpFd, F_GETFL, 0);
    fcntl(g_iUdpFd, F_SETFL, iFlags | O_NONBLOCK);
    int result =  bind(g_iUdpFd, (struct sockaddr *)&localAddr, sizeof(localAddr));
    if(result < 0)
    {

       WriteLog( "Server:Can't bind local address! 9004\n");
        return false;
    }
    g_client_info.clear();
    WriteLog( "start..." );

    FD_ZERO( &g_set );
    ConnInfo conn;
    conn.iFd = g_iServerSocketFd;
    conn.iLastTime = time(NULL);
    g_servlist.push_back(conn);
    conn.iFd = g_iUdpFd;
    conn.iLastTime = time(NULL);
    g_servlist.push_back(conn);
    FD_SET(g_iServerSocketFd, &g_set);
    FD_SET(g_iUdpFd, &g_set);
    g_iMaxFd = (g_iServerSocketFd > g_iUdpFd? g_iServerSocketFd : g_iUdpFd);
    
    while(1)
    {
        struct timeval ptv;
        ptv.tv_sec = 30;
        ptv.tv_usec = 0;
        fd_set fdset = g_set;
        int iRet = select(g_iMaxFd+1,  &fdset,  NULL,  NULL,  &ptv); 
        if(iRet > 0)
        {
            for(list<ConnInfo>::iterator it=g_servlist.begin();it!=g_servlist.end();it++)
            {
                int fd = it->iFd;
                if(FD_ISSET(fd,&fdset))
                {
                    if(fd == g_iServerSocketFd)
                    {
                        struct sockaddr_in clientAddr;
                        unsigned int nameLen = sizeof(clientAddr);
                        int clientSock = accept( g_iServerSocketFd, (sockaddr*)&clientAddr, &nameLen );
                        printf( "get accept:%d\n" , clientSock);
                        if(clientSock > 0)
                        {
                            conn.iFd = clientSock;
                            conn.iLastTime = time(NULL);
                            conn.addr = clientAddr;
                            conn.addrLen = nameLen;
                            g_servlist.push_back(conn);
                            FD_SET(clientSock, &g_set);
                            if(clientSock > g_iMaxFd) g_iMaxFd = clientSock;
                        }
                    }
                    else
                    {
                        struct sockaddr_in  remoteAddr;
                        socklen_t remoteAddrLength = sizeof(remoteAddr);
                        char szData[24] = {0};
                        int iLen = recvfrom(fd,szData,24,0,(struct sockaddr *)&remoteAddr, &remoteAddrLength);
                        if(iLen <=0)
                        {
                            close(fd);
                            it = g_servlist.erase(it);
                            FD_CLR(fd,&g_set);

                           printf( "socket break:%d" , fd);
                            break;
                        }
                        printf( "fd:%d,recv:%s\n" , fd , szData );
                                                
                        if(strncmp(szData,"LOGIN",5)==0)
                        {
                            it->iLastTime = time(NULL);
                            it->addr = remoteAddr;
                            it->addrLen = remoteAddrLength;
                            string strClientId = szData+6;
                            memset(szData,0,sizeof(szData));
                            strncpy(szData,"LOGIN_RESP_HEIGHT",sizeof(szData));
                            sendto(fd,szData,strlen(szData),0,(struct sockaddr *)&remoteAddr ,remoteAddrLength);
                            string strSign = "000000000000000000";
                            string strVersion = "1.0";
                            map<string,ConnInfo>::iterator p = g_client_info.find(strClientId);
                            if(p == g_client_info.end())                                
                                g_client_info[strClientId] = *it;
                            else
                            {
                                p->second.iLastTime = it->iLastTime;
                                p->second.addr = remoteAddr;
                                p->second.addrLen = remoteAddrLength;
                            }
                        }
                        else if(strncmp(szData,"ACK",3)==0)
                        {
                            it->iLastTime = time(NULL);
                            it->addr = remoteAddr;
                            it->addrLen = remoteAddrLength;
                            string strClientId = szData+4;
                            memset(szData,0,sizeof(szData));
                            strncpy(szData,"ACK_RESP",sizeof(szData));
                            sendto(fd,szData,strlen(szData),0,(struct sockaddr *)&remoteAddr ,remoteAddrLength);
                            map<string,ConnInfo>::iterator p = g_client_info.find(strClientId);
                            if(p != g_client_info.end())
                            {
                                p->second.iLastTime = it->iLastTime;
                                p->second.addr = remoteAddr;
                                p->second.addrLen = remoteAddrLength;
                            }
                        }
                        else if(strncmp(szData,"CTRL",4)==0)
                        {
                            memset(szData,0,sizeof(szData));
                            strncpy(szData,"OPEN",4);
                            for(list<ConnInfo>::iterator pit=g_servlist.begin();pit!=g_servlist.end();pit++)
                            {
                                if(pit->iFd != g_iServerSocketFd)
                                {
                                    printf( "send to fd:%d\n" ,pit->iFd);
                                    sendto(pit->iFd,szData,strlen(szData),0,(struct sockaddr *)&pit->addr ,pit->addrLen);
                                }
                            }
                            sendto(fd,szData,strlen(szData),0,(struct sockaddr *)&remoteAddr ,remoteAddrLength);
                        }
                        else if(strncmp(szData,"ORDER|",6)==0)//收到手机端的开门指令,转发给esp8266
                        {
                            stringstream ss(szData);
                            string strOrder,strClientId,strOP;
                            getline(ss,strOrder,'|');
                            getline(ss,strClientId,'|');
                            getline(ss,strOP,'|'); 
                            map<string,ConnInfo>::iterator p = g_client_info.find(strClientId);
                            if(p == g_client_info.end())
                               printf("can not find clientid:%s\n" , strClientId);
                            else
                            {
                               printf( "send to fd:%d,op:%s\n" , p->second.iFd ,strOP.c_str());
                                sendto(p->second.iFd,strOP.c_str(),strOP.length(),0,(struct sockaddr *)&p->second.addr ,p->second.addrLen);
                            }
                            sendto(fd,"OK",2,0,0,0);
                        }
                        else if(strncmp(szData,"OPEN_RESP",9)==0)
                        {
                            string strClientId = szData+10;
                            map<string,ConnInfo>::iterator p = g_client_info.find(strClientId);
                            if(p != g_client_info.end())
                            {
                                p->second.iLastTime = time(NULL);
                            }
                        }
                        else if(strncmp(szData,"HEIGHT_RESP",11)==0)
                        {
                            string strClientId = szData+12;
                        }
                        else if(strncmp(szData,"LOW_RESP",8)==0)
                        {
                            string strClientId = szData+9;
                        }
                        else
                        {
                            close(fd);
                            it = g_servlist.erase(it);
                            FD_CLR(fd,&g_set);
                           printf( "unbknow command socket close" );
                            break;
                        }
                    }
                }
            }
        }
        else if(iRet == 0)
        {
            for(list<ConnInfo>::iterator it=g_servlist.begin();it!=g_servlist.end();)
            {
                if( it->iFd != g_iUdpFd && it->iFd != g_iServerSocketFd  && difftime(time(NULL),it->iLastTime) > 120)
                {
                   printf( "clean not active fd:%d\n" , it->iFd);
                    FD_CLR(it->iFd,&g_set);
                    close(it->iFd);
                    it = g_servlist.erase(it);    
                }
                else
                    it++;
            }
        }
        else
            ;
    }
}


int CanReceive(int fd,int p_iUsec)
{
    fd_set rf;
    struct timeval tox;
    
    FD_ZERO(&rf);
    FD_SET(fd, &rf);
    int i = p_iUsec / 1000 / 1000;
    tox.tv_sec = i;
    tox.tv_usec = p_iUsec % (1000 * 1000);
    //return select(fd + 1, &rf, NULL, NULL, &tox);
    return select(FD_SETSIZE, &rf, NULL, NULL, &tox);
}
int CanSend(int fd,int p_iUsec)
{
    fd_set rf;
    struct timeval tox;
    FD_ZERO(&rf);
    FD_SET(fd, &rf);
    int i = p_iUsec / 1000 / 1000;
    tox.tv_sec = i;
    tox.tv_usec = p_iUsec % (1000 * 1000);
    return select(FD_SETSIZE, NULL, &rf, NULL, &tox);
    //return select(fd + 1, NULL, &rf, NULL, &tox);
}
 

  • 7
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
物联网是指通过无线通信技术将各种设备、物品互联互通,实现信息共享和远程控制的网络系统。STM32开发板是一种常用的微控制器开发板,其可以与各种外部设备相连,如传感器、执行器等。在物联网应用中,使用STM32开发板进行设备的控制和数据的采集十分常见。 为了方便用户对物联网设备进行控制,可以使用App、小程序或者Web页面等方式实现远程控制。在本场景中,我们使用了STM32开发板、W5500以太网模块和ESP8266 WiFi模块。 W5500是一款硬件以太网控制器,它可以用于将STM32开发板连接到网络。通过W5500,STM32可以通过Ethernet协议与Internet进行通信。用户可以通过编写STM32的程序,实现与云服务器的数据交互与远程控制。 同时,我们还可以使用ESP8266模块连接到STM32开发板,使得STM32具备WiFi通信能力。ESP8266可以连接到无线网络,并提供与云服务器的通信接口。使用ESP8266模块,我们可以使用HTTP或MQTT等协议与互联网进行通信,实现物联网设备的远程控制和OTA(Over-The-Air)升级。 OTA升级指的是通过网络向设备更新固件,而不需要将设备连接到计算机进行有线升级。在物联网应用中,OTA升级可以实现灵活的固件更新,为设备带来更多的功能和修复漏洞。使用OTA升级,我们可以通过网络将固件更新的指令发送到STM32开发板,然后通过W5500或ESP8266模块将固件文件下载到设备,最后进行固件更新。这样,设备的固件可以实时更新,同时不需要用户手动连接设备和计算机。 总之,通过使用STM32开发板、W5500以太网模块、ESP8266 WiFi模块以及相应的App、小程序或者Web页面,我们可以实现物联网设备的远程控制和OTA升级。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lijiteng

好心啦,福心啦.打赏网络乞丐啦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值