Google Code Prettify

2016年10月12日 星期三

[Arduino + Android]ESP8266 arduino + android studio 設計應用(一)

最近在使用這塊便宜的ESP8266 WIFI,但是說真的Farmer底子並不好,所以很多東西看不太懂,不過還是有成功一些小東西,在這裡也記錄起來 ,也歡迎大家一起參考應用,畢竟資料難找(?),其實是因為英文看不懂 哈哈 ..

廢話不多說,開始介紹ESP8266應用



會有人問我,ESP8266 有這麼多塊板子,有甚麼推薦與差異嗎??

其實Farmer也不太懂硬體的部分,就是傻傻地買了,不過大家可以去露天看看並且比較一下CP,我是有固定與一家購買,在這就不打廣告了,如果有想知道去哪買再偷偷問我啊~

對了,如果家中沒有 USB轉 TTL、USB轉 Serial等名稱的轉換器,請記得順便購買。

Farmer 購買 ESP 8266 ESP-01 這塊,如下圖,
參考圖:google,如有問題,馬上刪除,謝謝。


[ 一、韌體 更新/退回 版本 & AT測試 Realterm ]

剛送來的時候 胞率 115200,所以硬體的韌體要刷一下啦!當然不是每個人的應用都需要刷韌體,請自行參考應用。

在刷韌體中有遇到狀況,朋友也遇到很多狀況,在這裡提醒一下大家,再刷韌體的時候,
電源電流!電源電流!電源電流!
一定要穩定3.3V,電流也一定要穩,請外接電源,以免刷韌體失敗,聽說有朋友刷韌體失敗導致壞掉,所以真的很重要!

而AT測試,可使用 Realterm 做測試,

以上這些可參考兩位神人文章:

【技術教學】打造Wifi遙控車(之一):使用 ESP8266進行 Wifi無線通訊
http://lets-make-games.blogspot.tw/2015/04/wifi-esp8266-wifi.html

小狐狸事務所 - ESP8266 更新韌體
http://yhhuang1966.blogspot.tw/2015/08/esp8266.html

(Farmer很懶,有巨人在,就參考巨人吧 :D )

[ 二、 ARDUINO CODE]


#include <SoftwareSerial.h>
#define DEBUG true

/*
Farmer使用mega版,所以RXTX使用Serial1(D19、D18)
如果使用uno版可以修改下方註解,因為預設RXTX是電腦燒入時會應用,
所以使用的話,燒入記得要拔除,但怕麻煩,可以改變腳位使用,即可避免燒入衝突。
*/
HardwareSerial& esp8266=Serial1;
//SoftwareSerial esp8266(10,11); 

void setup()
{
  Serial.begin(9600);
  esp8266.begin(9600); // esp韌體的胞率,若為115200,請記得修改
  
  // 使用13LED先做測試
  pinMode(13,OUTPUT);
  digitalWrite(13,LOW);
   
  sendCommand("AT+RST\r\n",2000,DEBUG); // reset module
  sendCommand("AT+CWMODE=1\r\n",1000,DEBUG); // configure as access point
  
  /***************************************************************/
  /*SSID、PASSWD請輸入您要連接的AP(如家中數據機或是手機分享網路),這邊一定要修改*/
  sendCommand("AT+CWJAP=\"SSID\",\"PASSWD\"\r\n",3000,DEBUG);
  delay(10000);
  
  sendCommand("AT+CIFSR\r\n",1000,DEBUG); // get ip address
  sendCommand("AT+CIPMUX=1\r\n",1000,DEBUG); // configure for multiple connections
  sendCommand("AT+CIPSERVER=1,80\r\n",1000,DEBUG); // turn on server on port 80
  Serial.println("Server Ready");
}
void loop()
{
  if(esp8266.available()) // 檢查ESP是否有傳送
  {
    if(esp8266.find("+IPD,"))
    {
     delay(1000); // wait for the serial buffer to fill up (read all the serial data)
     // get the connection id so that we can then disconnect
     int connectionId = esp8266.read()-48; //  ASCII 48 十進制 為 0
          
     esp8266.find("pin="); // advance cursor to "pin="
          
     int pinNumber = (esp8266.read()-48);
     int secondNumber = (esp8266.read()-48);
     if(secondNumber>=0 && secondNumber<=9)
     {
      pinNumber*=10;
      pinNumber +=secondNumber; 
     }
     
     digitalWrite(pinNumber, !digitalRead(pinNumber)); // toggle pin    
     
     // build string that is send back to device that is requesting pin toggle
     String content;
     content = "Pin ";
     content += pinNumber;
     content += " is ";
     
     if(digitalRead(pinNumber))
     {
       content += "ON";
     }
     else
     {
       content += "OFF";
     }
     
     sendHTTPResponse(connectionId,content);
     
     // make close command
     String closeCommand = "AT+CIPCLOSE="; 
     closeCommand+=connectionId; // append connection id
     closeCommand+="\r\n";
     
     sendCommand(closeCommand,1000,DEBUG); // close connection
    }
  }
}
/*
* Name: sendData
* Description: Function used to send data to ESP8266.
* Params: command - the data/command to send; timeout - the time to wait for a response; debug - print to Serial window?(true = yes, false = no)
* Returns: The response from the esp8266 (if there is a reponse)
*/
String sendData(String command, const int timeout, boolean debug)
{
    String response = "";
    
    int dataSize = command.length();
    char data[dataSize];
    command.toCharArray(data,dataSize);
           
    esp8266.write(data,dataSize); // send the read character to the esp8266
    if(debug)
    {
      Serial.println("\r\n====== HTTP Response From Arduino ======");
      Serial.write(data,dataSize);
      Serial.println("\r\n========================================");
    }
    
    long int time = millis();
    
    while( (time+timeout) > millis())
    {
      while(esp8266.available())
      {
        
        // The esp has data so display its output to the serial window 
        char c = esp8266.read(); // read the next character.
        response+=c;
      }  
    }
    
    if(debug)
    {
      Serial.print(response);
    }
    
    return response;
}
/*
* Name: sendHTTPResponse
* Description: Function that sends HTTP 200, HTML UTF-8 response
*/
void sendHTTPResponse(int connectionId, String content)
{
     
     // build HTTP response
     String httpResponse;
     String httpHeader;
     // HTTP Header
     httpHeader = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n"; 
     httpHeader += "Content-Length: ";
     httpHeader += content.length();
     httpHeader += "\r\n";
     httpHeader +="Connection: close\r\n\r\n";
     httpResponse = httpHeader + content + " "; // There is a bug in this code: the last character of "content" is not sent, I cheated by adding this extra space
     sendCIPData(connectionId,httpResponse);
}
/*
* Name: sendCIPDATA
* Description: sends a CIPSEND=<connectionId>,<data> command
*
*/
void sendCIPData(int connectionId, String data)
{
   String cipSend = "AT+CIPSEND=";
   cipSend += connectionId;
   cipSend += ",";
   cipSend +=data.length();
   cipSend +="\r\n";
   sendCommand(cipSend,1000,DEBUG);
   sendData(data,1000,DEBUG);
}
/*
* Name: sendCommand
* Description: Function used to send data to ESP8266.
* Params: command - the data/command to send; timeout - the time to wait for a response; debug - print to Serial window?(true = yes, false = no)
* Returns: The response from the esp8266 (if there is a reponse)
*/
String sendCommand(String command, const int timeout, boolean debug)
{
    String response = "";
           
    esp8266.print(command); // send the read character to the esp8266
    
    long int time = millis();
    
    while( (time+timeout) > millis())
    {
      while(esp8266.available())
      {
        
        // The esp has data so display its output to the serial window 
        char c = esp8266.read(); // read the next character.
        response+=c;
      }  
    }
    
    if(debug)
    {
      Serial.print(response);
    }
    
    return response;
}


[ 三、 ANDROID STUDIO CODE]

Manifest File


這裡主要是追加這行,這樣才可以開啟網路權限使用
<uses-permission android:name="android.permission.INTERNET" />

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.roy.arduinowifitext">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


Layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.roy.arduinowifitext.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="IP Address:"
        android:id="@+id/textView"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="25dp" />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="e.g. 192.168.0.10"
        android:text="192.168.43.176"
        android:id="@+id/editTextIPAddress"
        android:layout_marginTop="25dp"
        android:layout_below="@+id/textView"
        android:layout_alignParentEnd="true" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Port Number:"
        android:id="@+id/textView2"
        android:layout_below="@+id/editTextIPAddress"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="23dp" />

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="number"
        android:ems="10"
        android:hint="e.g. 80"
        android:text="80"
        android:id="@+id/editTextPortNumber"
        android:layout_below="@+id/textView2"
        android:layout_alignParentEnd="true"
        android:layout_marginTop="22dp" />
    
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Pin 13"
        android:id="@+id/buttonPin13"
        android:layout_marginBottom="48dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true" />
</RelativeLayout>


Main 

package com.example.roy.arduinowifitext;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;

public class MainActivity extends AppCompatActivity {

    public final static String PREF_IP = "PREF_IP_ADDRESS";
    public final static String PREF_PORT = "PREF_PORT_NUMBER";
    // declare buttons and text inputs
    private Button buttonPin13;
    private EditText editTextIPAddress, editTextPortNumber;
    // shared preferences objects used to save the IP address and port so that the user doesn't have to
    // type them next time he/she opens the app.
    SharedPreferences.Editor editor;
    SharedPreferences sharedPreferences;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        sharedPreferences = getSharedPreferences("HTTP_HELPER_PREFS",Context.MODE_PRIVATE);
        editor = sharedPreferences.edit();

        // assign buttons
        buttonPin13 = (Button)findViewById(R.id.buttonPin13);

        // assign text inputs
        editTextIPAddress = (EditText)findViewById(R.id.editTextIPAddress);
        editTextPortNumber = (EditText)findViewById(R.id.editTextPortNumber);

        // set button listener (this class)
        buttonPin13.setOnClickListener(btnOnOffClickListener);

        // get the IP address and port number from the last time the user used the app,
        // put an empty string "" is this is the first time.
        editTextIPAddress.setText(sharedPreferences.getString(PREF_IP,""));
        editTextPortNumber.setText(sharedPreferences.getString(PREF_PORT,""));
    }

    View.OnClickListener btnOnOffClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            // get the pin number
            String parameterValue = "";
            // get the ip address
            String ipAddress = editTextIPAddress.getText().toString().trim();
            // get the port number
            String portNumber = editTextPortNumber.getText().toString().trim();


            // save the IP address and port for the next time the app is used
            editor.putString(PREF_IP, ipAddress); // set the ip address value to save
            editor.putString(PREF_PORT, portNumber); // set the port number to save
            editor.commit(); // save the IP and PORT

            // get the pin number from the button that was clicked
            if (view.getId() == buttonPin13.getId()) {
                parameterValue = "13";
            }


            // execute HTTP request
            if (ipAddress.length() > 0 && portNumber.length() > 0) {
                new HttpRequestAsyncTask(
                        view.getContext(), parameterValue, ipAddress, portNumber, "pin"
                ).execute();
            }
        }
    };

    /**
     * Description: Send an HTTP Get request to a specified ip address and port.
     * Also send a parameter "parameterName" with the value of "parameterValue".
     * @param parameterValue the pin number to toggle
     * @param ipAddress the ip address to send the request to
     * @param portNumber the port number of the ip address
     * @param parameterName
     * @return The ip address' reply text, or an ERROR message is it fails to receive one
     */
    public String sendRequest(String parameterValue, String ipAddress, String portNumber, String parameterName) {
        String serverResponse = "ERROR";

        try {

            HttpClient httpclient = new DefaultHttpClient(); // create an HTTP client
            // define the URL e.g. http://myIpaddress:myport/?pin=13 (to toggle pin 13 for example)
            URI website = new URI("http://"+ipAddress+":"+portNumber+"/?"+parameterName+"="+parameterValue);
            HttpGet getRequest = new HttpGet(); // create an HTTP GET object
            getRequest.setURI(website); // set the URL of the GET request
            HttpResponse response = httpclient.execute(getRequest); // execute the request
            // get the ip address server's reply
            InputStream content = null;
            content = response.getEntity().getContent();
            BufferedReader in = new BufferedReader(new InputStreamReader(
                    content
            ));
            serverResponse = in.readLine();
            // Close the connection
            content.close();
        } catch (ClientProtocolException e) {
            // HTTP error
            serverResponse = e.getMessage();
            e.printStackTrace();
        } catch (IOException e) {
            // IO error
            serverResponse = e.getMessage();
            e.printStackTrace();
        } catch (URISyntaxException e) {
            // URL syntax error
            serverResponse = e.getMessage();
            e.printStackTrace();
        }
        // return the server's reply/response text
        return serverResponse;
    }


    /**
     * An AsyncTask is needed to execute HTTP requests in the background so that they do not
     * block the user interface.
     */
    private class HttpRequestAsyncTask extends AsyncTask<Void, Void, Void> {

        // declare variables needed
        private String requestReply,ipAddress, portNumber;
        private Context context;
        private AlertDialog alertDialog;
        private String parameter;
        private String parameterValue;

        /**
         * Description: The asyncTask class constructor. Assigns the values used in its other methods.
         * @param context the application context, needed to create the dialog
         * @param parameterValue the pin number to toggle
         * @param ipAddress the ip address to send the request to
         * @param portNumber the port number of the ip address
         */
        public HttpRequestAsyncTask(Context context, String parameterValue, String ipAddress, String portNumber, String parameter)
        {
            this.context = context;

            alertDialog = new AlertDialog.Builder(this.context)
                    .setTitle("HTTP Response From IP Address:")
                    .setCancelable(true)
                    .create();

            this.ipAddress = ipAddress;
            this.parameterValue = parameterValue;
            this.portNumber = portNumber;
            this.parameter = parameter;
        }

        /**
         * Name: doInBackground
         * Description: Sends the request to the ip address
         * @param voids
         * @return
         */
        @Override
        protected Void doInBackground(Void... voids) {
            alertDialog.setMessage("Data sent, waiting for reply from server...");
            if(!alertDialog.isShowing())
            {
                alertDialog.show();
            }
            requestReply = sendRequest(parameterValue,ipAddress,portNumber, parameter);
            return null;
        }

        /**
         * Name: onPostExecute
         * Description: This function is executed after the HTTP request returns from the ip address.
         * The function sets the dialog's message with the reply text from the server and display the dialog
         * if it's not displayed already (in case it was closed by accident);
         * @param aVoid void parameter
         */
        @Override
        protected void onPostExecute(Void aVoid) {
            alertDialog.setMessage(requestReply);
            if(!alertDialog.isShowing())
            {
                alertDialog.show(); // show dialog
            }
        }

        /**
         * Name: onPreExecute
         * Description: This function is executed before the HTTP request is sent to ip address.
         * The function will set the dialog's message and display the dialog.
         */
        @Override
        protected void onPreExecute() {
            alertDialog.setMessage("Sending data to server, please wait...");
            if(!alertDialog.isShowing())
            {
                alertDialog.show();
            }
        }

    }
}


這邊可能會發生警告狀況,因為沒有帶入lib,所以Org.apache皆無法使用,聽說在android studio 6 就將 org.apache.http.legacy 換至 HTTP URL CONNECTION。

 但Farmer還是使用org.apache.http.legacy,且做法跟上圖有所差異,我是直接去X:\Android\sdk\platforms\android-23\optional,可以利用電腦的搜尋 "org.apache.http.legacy.jar"

或是,在這裡直接下載


如果以上都沒有問題,各位就可以試試看,是否可以使用



以下為Farmer的code file




以上皆參考


資料測試改寫,如有任何版權問題,請告知,立即刪除,謝謝

沒有留言:

張貼留言