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

news/2025/3/21 6:12:59/

        近日笔者自己动手修理自家的门铃时,发现只要接通开门的电源线,就可以打开楼宇的大门了,突发奇想:在门铃引出线加装继电器就可以用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);
}
 


http://www.ppmy.cn/news/212870.html

相关文章

远程遥控小车搭建记录

22年国庆期间&#xff0c;无意从抖音上发现远程遥控小车已经很普及了&#xff0c;包含了摄像头、喊话器、闪光灯控制&#xff0c;系统均是单片机控制&#xff0c;再叠加一个360度摄像头&#xff0c;基本是两个系统的叠加&#xff0c;也有一些商业化的系统&#xff0c;硬件软件云…

基于 STM32 远程控制的多功能门锁

本项目有指纹识别、动态密码、普通钥匙以及管理员特有的微信等开 门方式&#xff0c;实验室人员可直接指纹识别进入&#xff1b;管理员手机微信获取的动态密 码给非实验室人员&#xff0c;具有随机性&#xff0c;不确定性&#xff0c;且隐私性较高&#xff0c;同时管理员 手机可…

智汀教你如何用手机远程控制智能门锁

前面跟大家说了那么多关于智能门锁的知识点&#xff0c;今天就跟大家讲一下如何用手机控制智能门锁吧&#xff1a; 以下操作基于拥有智汀智慧中心 Smart Assistant (硬件&#xff0c;简称SA)&#xff0c;通过 SA 加入不同品牌的插件包&#xff0c;从而达到联动不同品牌的智能家…

HTML <details> 标签

实例 关于文档的细节&#xff1a; <details> <summary>Copyright 2011.</summary> <p>All pages and graphics on this web site are the property of W3School.</p> </details>浏览器支持 元素ChromeIEFirefoxSafariOpera<details&…

世界上手机号码最长和最短的国家

现在手机普及率非常之高&#xff0c;基本上人手至少一个手机&#xff0c;那么哪个国家的手机号码最长呢&#xff1f;其实世界上最长的电话号码&#xff0c;是11位数的中国手机号码。为什么手机号码是11位呢&#xff1f; 最短的是7位数&#xff0c;加拿大。 1、号码格式决定 …

美国人用什么android手机,美国过半消费者使用智能手机 Android占48.5%

各系统市场份额图(腾讯科技配图) 不同种族手机使用情况(腾讯科技配图) 腾讯科技讯(萧谔)北京时间5月8日消息&#xff0c;据国外媒体报道&#xff0c;尼尔森发表最新报告称&#xff0c;2012年3月美国50.4%的消费者在使用智能手机&#xff0c;比2012年12月时提高了3个百分点。 尼…

手机CPU出货量Top20型号及参数

转自&#xff1a;https://mp.weixin.qq.com/s/B9JigmDaB4pm5h0mCkUaiA

5G手机芯片简史

时间过得真快&#xff0c;还有一个多月&#xff0c;2020年就要结束了。 今年&#xff0c;是国内5G网络全面商用的第一年。虽然我们遭受了新冠疫情的冲击&#xff0c;但5G的建设步伐并没有受到太多影响&#xff08;反而有所刺激&#xff09;。 5G基站 根据工信部副部长刘烈宏前天…