2017年5月21日 星期日

第一章:Arduino IDE設計ESP8266 AP Station mode + MQTT

RD腦說:我們就先設計ESP8266 AP Station modeAndroid手機對連
這樣就可以百分百連接到AP!

具體設計流程如下
1、先讓ESP8266初始就進入AP mode
2、使用AndroidSocketESP8266設定帳號密碼
3、ESP8266關閉AP mode,進入Station mode
4、接收BLE掃瞄的值
5、將掃進來的值用MQTTPublishServer上丟
6、Subscribe Server 回傳的值

寫法如下
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <SoftwareSerial.h>

WiFiServer server(5000); //Initialize the server on Port 5000
int flag1=1,flag2=0,flag3=0,flag4=0,flag5=0; //待會往下看就知道為什麼要有5flag,這是當作開關使用
const char* Topic = "hello/world";//MQTT要設定Topic,先隨便設定
const char* mqtt_server = "192.168.1.19";//local端的IP

const char *array[5], *BLE_UID[5]; //array是拿來放Android丟來的資料,BLE_UID是拿來放BLE丟上來的資料
   int i = 0;
  

WiFiClient espClient;
PubSubClient client(espClient);
//下面是寫MQTT收到的回傳資料
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

}

void reconnect() {//這裡是寫,當變成Station mode時,去連接MQTTServer
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish(Topic, "hello world");
      // ... and resubscribe
      client.subscribe(Topic);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  delay(1000);
  Serial.begin(115200);
      Serial.println();
  Serial.print("Configuring access point...");
WiFi.mode(WIFI_AP); //ESP8266變成AP mode
WiFi.softAP("Simple Care", ""); // 一開始ESP8266變成AP的名稱

  IPAddress myIP = WiFi.softAPIP();
  Serial.println();
  Serial.print("AP IP address: ");
  Serial.println(myIP);
 
server.begin(); // Start the HTTP Server


}

void loop() { //這裡共有5flag
  if (flag1==1){
    // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
 
  // 如果連上了,就shownew client連進來了
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
 
  // Read the first line of the request
  String req = client.readString();
  char charBuf[50];//for string to char
  int req_len = req.length() + 1;
  req.toCharArray(charBuf, req_len); 
  Serial.println(charBuf);
  client.flush();
//以下是把Android送來的socketstrok切割放入array的陣列裡
char *p = strtok (charBuf, "\\");
    while (p != NULL)
    {
        array[i++] = p;
        p = strtok (NULL, "\\");
    }
       WiFi.disconnect(); 
  WiFi.softAPdisconnect(true);
    WiFi.mode(WIFI_OFF);

    flag1=0;
    flag2=1;
}

if (flag2==1)
{
Serial.println();
    Serial.println(array[0]);//印出android第一個值,拿來Debug
    Serial.println();
    Serial.println(array[1]); //印出android第二個值,拿來Debug
   
  WiFi.mode(WIFI_STA);//ESP8266變成Station mode
  delay(1000);
  WiFi.begin(array[0], array[1]);//設定連接上家中的AP的帳號密碼
  Serial.println("Wifi station mode");

    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  delay(500);
  Serial.println("\\G\\O\\]");//連上AP傳個\G\O\MCUBLE叫起來開始Scan

flag2=0;
flag3=1;
 
  }

  if (flag3==1)
  {
    String s = "";
    char a[30];
    int i=0;
    while (Serial.available()) {//uart RX的值讀進來
        char c = Serial.read();
        if(c!='\n'){
            s += c;
            a[i]=c;
            i++;
        }
       
        delay(5); //沒有延遲的話 UART 串口速度會跟不上Arduino的速度,會導致資料不完整
    }

    if(s!=""){
        i=0;

  char *p = strtok (a, "\\");//分割讀進來的值
    while (p != NULL)
    {
        BLE_UID[i++] = p;
        p = strtok (NULL, "\\");
    }
    flag3=0;
    flag4=1;
    }

    }

   
if (flag4==1)
{
  Topic = "hello/add_data";//這裡的Topicadd_data
    if (!client.connected()) {
    reconnect();
  }
  client.loop();

    char str[30];
    strcat (str,"\\");
    strcat (str,array[2]);
    strcat (str,"\\");
    strcat (str,array[3]);
    strcat (str,"\\");
    strcat (str,array[4]);

    client.publish(Topic, str);//add_data送上Cloudadd_data指的是初始,使用者給這個主機叫什麼名字,例如主機名叫room,代表這東西放在房間,以及gps位置,原本還想上傳WIFI MAC,但浪費資源就不做

    flag4=0;
    flag5=1;
 
  }

 if (flag5==1)
{
Topic = "hello/update_BLE_data";//這裡是代表Topic要上傳BLE Scan的資料
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  if (Serial.available() > 0) {
String incomingByte = Serial.readString();
Serial.println(incomingByte);

  char charBuf[50];//for string to char
  int req_len = incomingByte.length() + 1; //for string to char
  incomingByte.toCharArray(charBuf, req_len);//for string to char

    Serial.print("Publish message: ");
    Serial.println(charBuf);
    client.publish(Topic, charBuf);//BLE Scan的資料傳到Server
  }
}
}
 
PM腦說:如此ESP8266+MQTT就完成了,但要怎麼讓它動?

RD腦回應:別急! 還要搭配AndroidMQTT Server才會動!
接下來我們先做Android的部份,就可以百分百連到AP
這樣就不怕北美的使用者配不上網就退貨啦!
 

本體:讀者也許會發現Topichello/xxx,這裡我們暫時把主機叫作hello
將來要改為BLE的唯一碼,也就是UID,這樣每個燈座都有唯一碼
MQTT就不會認錯人,把小明叫成小黃

註:如果不會寫APP,也可以改用Sokit這個軟體測試

1 則留言:

  1. 請問版主 當wifi密碼打錯,連不到只能一直在while迴圈裡,這時手機已經斷開AP裝置連線了,有辦法錯誤時不斷,手機可以再發訊息給裝置嗎?

    回覆刪除

FB設定搶先看的方式

設定搶先看的兩種方式 A1. 先到我家的日常粉絲團按下 …( 紅框處 ) A2. 按下追蹤中 ( 紅框處 ) A3. 按下搶先看 ( 紅框處 ) A4. 完成!!! 另一種方式 ...