Arduino+ESP8266自动配网并上传温湿度、光照强度到OneNET

前言
    从接触ESP8266到现在有一段时间了,也感受到ESP8266的强大,其高性价比给极客者们带来了极大的福音。之前用ESP8266改装了一部遥控车,使其能用手机控制,手机app是用易安卓编制的,遥控车视频挂到b站了,视频地址: https://www.bilibili.com/video/av20141857?from=search&seid=10781143291446850224
    这次是打算用Arduino+ESP8266来实现智能配网以及通过EDP协议上传温度、湿度和光照强度等数据到OneNET平台,也可以用EDP下发命令来实现远程控制。
所需材料
    Arduino_pro_mini         1
    ESP8266-12F              1
     USB-TTL串口下载模块       1
    DHT11温湿度传感器        1
    面包板及杜板线           若干
    光敏电阻                 1
    电阻及发光二极管等       若干
智能配网(Smart Config
SmartConfig的过程:
    1wifi模块通电,没有可用的wifi, 进入混杂模式,开始监(和谐)听覆盖范围内所有WiFi数据帧
    2、手机APP或微信端发送包含WIFI用户名和WIFI密码的UDP广播包或者组播包;
    3、智能终端的WIFI芯片可以接收到该UDP包,只要知道UDP的组织形式,就可以通过接收到的UDP包解密出WIFI用户名和密码;
    4、然后智能硬件配置收到的WIFI用户名和密码到指定的WIFI AP(路由器)上。
    ESP8266可通过AT指令进入智能配网模式,我所用的AT固件是安信可推出的固件,可在安信可官网里 http://wiki.ai-thinker.com/esp8266/sdk 下载。配网的AT指令可参考安信可官网 http://wiki.ai-thinker.com/esp8266/examples/at_demo 里的步骤。通过将AT指令写在pro mini内,再通过外部按钮按下进入配网。
    pro mini通过软串口跟ESP8266通信,而ESP8266用的是3.3V电源,pro mini用的是5V电源,所以串口必须通过电平转换才行,由于身边暂时没有电平转换模块,所以只能通过分压来实现。经过实测,ESP8266跟pro mini软串口通信用115200波特率 会出现乱码,所以只能用9600波特率。
    分压和配网按钮接线图如下所示:

Arduino+ESP8266自动配网并上传温湿度、光照强度到OneNET_第1张图片 
程序如下:
#include      //使用软串口的库文件
#define configkey 2             //配网按钮,按住时候配网
#define configRED 7             //智能配网失败红灯亮起
#define configGREEN 8           //智能配网成功绿灯亮起
#define TcpLED 12               //OneNET的TCP连接灯
#define EdpLED 6                //OneNET的EDP连接灯
bool link;                      //判断智能配网是否成功
bool keyOK=1;                    //判断配网按钮是否可用
SoftwareSerial mySerial(10, 9);   // RX, TX
void setup() {
    mySerial.begin(9600);
    pinMode(configkey,INPUT);       //设置按键引脚为输入
    pinMode(configRED,OUTPUT);      //没连上无线网
    pinMode(configGREEN,OUTPUT);    //连上无线网
    pinMode(TcpLED,OUTPUT);         //连上OneNET的TCP
    pinMode(EdpLED,OUTPUT);         //连上OneNET的EDP
}
void loop() {
    int buttonState = digitalRead(configkey);
    if(buttonState==0 && keyOK==1){                   //按钮被按下时
        mySerial.print("+++");
        delay(100);
        mySerial.print("+++");
        delay(100);
        digitalWrite(TcpLED, HIGH);
        analogWrite(EdpLED,255);
        digitalWrite(configGREEN, HIGH);
        digitalWrite(configRED, HIGH);
        while (!doCmdOk("AT+CWSTARTSMART=3", "OK",5));   //启动智能配网
        t1=0;
        Serial.println("Smartconfig Start");
        digitalWrite(testLED, HIGH);
        while (!doConfigOK("smartconfig connected wifi"));
        t1=0;
    if(link==1){
      Serial.println("do Config OK");
      digitalWrite(configGREEN, LOW);
      digitalWrite(testLED, LOW);
      while (!doCmdOk("AT+CIPSTART=\"TCP\",\"183.230.40.39\",876","CONNECT",5));    //OneNET的TCP透传
      t1=0;
      digitalWrite(TcpLED, LOW);                      //tcp连接指示灯亮
      Serial.println("TCP connect OK");
      while (!doCmdOk("AT+CIPMODE=1", "OK",5));       //透传模式
      t1=0;
      while (!doCmdOk("AT+CIPSEND", ">",5));          //开始发送
      t1=0;
      link=1;
      edp_connect=0;
      keyOK=0;
      Serial.println("Start send");
    } else {
      Serial.println("do Config ERROR");
      digitalWrite(configRED, LOW);
      digitalWrite(testLED, LOW);
    }
    while (!doCmdOk("AT+CWSTOPSMART", "OK",5));         //不管ESP8266有没有连上wifi,都要释放内存
    t1=0;
  }
等待串口命令结果函数
booldoCmdOk(String data, char keyword[], int timeout){      //给ESP8266发送AT指令,在次数timeout范围内回应正确就返回TURE
     bool result = false;
     if (data != ""){                    
        mySerial.println(data);    //发送AT指令
        Serial.print("SEND: ");
        Serial.println(data);
     }
     while (!mySerial.available());      // 等待模块回复
     delay(200);
     if (mySerial.find(keyword)){        //返回值判断
        Serial.println("do cmd OK");
        response=1;
        result = true;
     } else {
        Serial.println("do cmd ERROR");
        result = false;
     }
     while(mySerial.read()>= 0){}   //清空串口接收缓存
     delay(800); //指令时间间隔
     t1++;
     if(t1>=timeout){         //超过设定时间,跳出循环,并返回回应判断response的值
        result = true;
        response=0;
     }
     return result;
}
配网时等待串口回复函数
booldoConfigOK(char keyword1[]){       //开启智能配网
     bool result1 = false;
     linktime=0;
     while (!mySerial.available()){  // 等待模块回复,10秒内要配网完成
        t1++;
        delay(1000);
        if(t1 >= 10){
           linktime=1;
           link=0;
           result1 = true;
           Serial.println("Config timeout");
           break;            //超过时间串口没收到信号就跳出
        }
     }
     if(linktime==0){
        delay(200);
        if (mySerial.find(keyword1)){   //返回值判断
           link=1;
           result1 = true;
        } else {
           link=0;
           result1 = false;
        }
        while(mySerial.read()>= 0){}   //清空串口接收缓存
        delay(500); //指令时间间隔
     }
     return result1;
}
EDP连接
    通过OneNET官网的库文件edp.c,可以很简单的连接到OneNET平台。当成功连接到平台时,会收到0x20 0x02 0x00 0x00,可以用这个信号来判断是否连接上。
if(link==1){               //当wifi连接上后,执行下面程序
    if (!edp_connect){
        while(mySerial.read()>= 0){}   //清空串口接收缓存
        packetSend(packetConnect(ID, KEY));             //发送EPD连接包
        while (!mySerial.available());                 //等待EDP连接应答
        delay(200);
        if ((tmp = mySerial.readBytes(rcv_pkt.data, sizeof(rcv_pkt.data))) > 0 ){    
          rcvDebug(rcv_pkt.data, tmp);
          if (rcv_pkt.data[0] == 0x20 && rcv_pkt.data[1] == 0x02 && rcv_pkt.data[2] == 0x00 && rcv_pkt.data[3] == 0x00)
          {
            edp_connect = 1;
            analogWrite(EdpLED,0);
            Serial.println("EDP connected.");
          }
          else
            Serial.println("EDP connect error.");
        }
        packetClear(&rcv_pkt);
      }
  }
光敏电阻
    光敏电阻通过分压,并通过模拟口A0输入到pro mini,接线电路图如下:
Arduino+ESP8266自动配网并上传温湿度、光照强度到OneNET_第2张图片
    通过分压后,读出的值在0~1024之间,数值越大,说明光线约弱,有点不太直观,于是我用个简单的函数将数值控制在0~100之间,并且数值越大,光线约强。
#define lightread A0      //光敏电阻读取的数值
ld_x=analogRead(lightread);   //光敏电阻接收的信号,信号是模拟值
ld=(4490-4*ld_x)/49; 
温湿度传感器
    温湿度传感器DHT11接线如下图所示:
Arduino+ESP8266自动配网并上传温湿度、光照强度到OneNET_第3张图片
#include      //使用DHT11的库文件
#define DHT11PIN A1    //DHT11温湿度模块数值
int wd;                //温度
int sd;                //湿度
int chk = DHT11.read(DHT11PIN);       //读DHT11
wd = (float)DHT11.temperature;        //获取温度
sd = (float)DHT11.humidity;           //获取湿度
上传数据到OneNET平台
if (edp_connect && trigger){
     Serial.print("temperature : "); Serial.println(wd);      //串口打印温度
     Serial.print("humidity : "); Serial.println(sd);         //串口打印湿度
     Serial.print("LigthRead_x : "); Serial.println(ld_x);    //串口打印亮度(读值)
     Serial.print("LigthRead_y : "); Serial.println(ld);      //串口打印亮度(计算值)
     Serial.println(" ");
     sprintf(wd1,"%d",wd);       //int型转换char型
     sprintf(sd1,"%d",sd);       //int型转换char型
     sprintf(ld1,"%d",ld);       //int型转换char型
     packetSend(packetDataSaveTrans(NULL, "tem", wd1));    //发送的数据必须为字符串
     delay(100);
     packetSend(packetDataSaveTrans(NULL, "hum", sd1));  
     delay(100);
     packetSend(packetDataSaveTrans(NULL, "light", ld1));
     delay(2000);
  }
EDP下发控制命令
    在OneNET平台开发者中心创建应用,在元件库里拉出一个开关按钮。按钮的EDP命令内容填datastr:{V}
    接收EDP命令并解析的程序:
while(mySerial.available()){     
     readEdpPkt(&rcv_pkt);
     if (isEdpPkt(&rcv_pkt)){
        pkt_type = rcv_pkt.data[0]; 
        switch (pkt_type){
           case CMDREQ:
           char edp_command[50];
           char edp_cmd_id[40];
           long id_len, cmd_len, rm_len;
           char datastr[20];
           char val[10];
           memset(edp_command, 0,sizeof(edp_command));    //置0
           memset(edp_cmd_id, 0,sizeof(edp_cmd_id));      //置0
           edpCommandReqParse(&rcv_pkt,edp_cmd_id, edp_command, &rm_len, &id_len, &cmd_len);  //按照EDP命令请求协议,解析数据
           Serial.print("rm_len: ");
           Serial.println(rm_len, DEC);
           delay(10);
           Serial.print("id_len: ");
           Serial.println(id_len, DEC);
           delay(10);
           Serial.print("cmd_len: ");
           Serial.println(cmd_len, DEC);
           delay(10);
           Serial.print("id: ");
           Serial.println(edp_cmd_id);
           delay(10);
           Serial.print("cmd: ");
           Serial.println(edp_command);
           sscanf(edp_command,"%[^:]:%s", datastr, val);
           if (atoi(val) == 1){         //atoi(),int转换为char,把一个整数转换为字符串。
                Serial.println("LEDon");   // 使Led亮
                digitalWrite(testLED, HIGH);
           }
           else if(atoi(val) == 0){
                Serial.println("LEDoff");   // 使Led灭
                digitalWrite(testLED, LOW);
           }
           packetSend(packetDataSaveTrans(NULL,datastr,val)); //将新数据值上传至数据流
           break;
      default:
           Serial.print("unknown type:");
           Serial.println(pkt_type, HEX);
           break;
           }
      }
  }
最后的接线图:
Arduino+ESP8266自动配网并上传温湿度、光照强度到OneNET_第4张图片
电脑端界面:
Arduino+ESP8266自动配网并上传温湿度、光照强度到OneNET_第5张图片

你可能感兴趣的:(Arduino)