原文链接:http://allaboutee.com/2015/01/20/esp8266-android-application-for-arduino-pin-control/
最近开发中用到需要 Arduino 与 Android 通过 wifi 通信,这里选择使用 ESP8266 模块,原因之一就是便宜,10几块钱就可以搞定,就是配置起来稍微有点麻烦,为此找了一些资料,但质量一直不是很好,最后通过 Google 了一把找到了靠谱的处理,考虑到可能连接外网困难,代码贴出来大家共同学习研究,
Arduino 部分
The Arduino code looks for the string +IPD whenever there is data available in the ESP8266, if the string is there then that means that a device (in this case the Android phone) is connecting to the ESP. The software then looks for the string pin=, then reads the pin number, toggles the pin, and sends back the string “Pin x is ON/OFF”.
The code is below and works with every pin number, but don’t use pins 0-3 since those are used for serial communication and the ESP8266 communication. Also, to get your ESP8266 and/or debug simply open the serial comm window in your Arduino ID
#include <SoftwareSerial.h>
#define DEBUG true
SoftwareSerial esp8266(2,3); // make RX Arduino line is pin 2, make TX Arduino line is pin 3.
// This means that you need to connect the TX line from the esp to the Arduino's pin 2
// and the RX line from the esp to the Arduino's pin 3
void setup()
{
Serial.begin(9600);
esp8266.begin(9600); // your esp's baud rate might be different
pinMode(11,OUTPUT);
digitalWrite(11,LOW);
pinMode(12,OUTPUT);
digitalWrite(12,LOW);
pinMode(13,OUTPUT);
digitalWrite(13,LOW);
pinMode(10,OUTPUT);
digitalWrite(10,LOW);
sendCommand("AT+RST\r\n",2000,DEBUG); // reset module
sendCommand("AT+CWMODE=1\r\n",1000,DEBUG); // configure as access point
sendCommand("AT+CWJAP=\"mySSID\",\"myPassword\"\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()) // check if the esp is sending a message
{
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; // subtract 48 because the read() function returns
// the ASCII decimal value and 0 (the first decimal number) starts at 48
esp8266.find("pin="); // advance cursor to "pin="
int pinNumber = (esp8266.read()-48); // get first number i.e. if the pin 13 then the 1st number is 1
int secondNumber = (esp8266.read()-48);
if(secondNumber>=0 && secondNumber<=9)
{
pinNumber*=10;
pinNumber +=secondNumber; // get second number, i.e. if the pin number is 13 then the 2nd number is 3, then add to the first number
}
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 部分
The activity file processes the user’s interaction with the UI. When a button a clicked the IP address and port number are saved so you don’t have to type them again, then the HTTP request is sent to the IP address specified with the parameter pin and the value of the pin.
package com.allaboutee.httphelper;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
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 HomeActivity extends Activity implements View.OnClickListener {
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 buttonPin11,buttonPin12,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_home);
sharedPreferences = getSharedPreferences("HTTP_HELPER_PREFS",Context.MODE_PRIVATE);
editor = sharedPreferences.edit();
// assign buttons
buttonPin11 = (Button)findViewById(R.id.buttonPin11);
buttonPin12 = (Button)findViewById(R.id.buttonPin12);
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)
buttonPin11.setOnClickListener(this);
buttonPin12.setOnClickListener(this);
buttonPin13.setOnClickListener(this);
// 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,""));
}
@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()==buttonPin11.getId())
{
parameterValue = "11";
}
else if(view.getId()==buttonPin12.getId())
{
parameterValue = "12";
}
else
{
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();
}
}
}
}
布局
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="IP Address:"
android:id="@+id/textView" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="e.g. 192.168.0.10"
android:id="@+id/editTextIPAddress" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Port Number:"
android:id="@+id/textView2" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:ems="10"
android:hint="e.g. 80"
android:id="@+id/editTextPortNumber" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pin 11"
android:id="@+id/buttonPin11" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pin 12"
android:id="@+id/buttonPin12" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Pin 13"
android:id="@+id/buttonPin13" />
</LinearLayout>
</ScrollView>
最后不要忘了添加 网络访问权限
<uses-permission android:name="android.permission.INTERNET" />