• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Apps Arduino + Android = Internet Garage Door. Works but could use input.

Like the title says, I've got an Arduino with an Asynclabs WiShield connected to the LAN that is also port-forwarded so it can connect anywhere there is an Internet connection. The app works but sometimes it hangs. I believe the problem is with threading inside the app but I'm not exactly sure how to go around fixing it. For now, like I said, it works I'm just wondering if anyone can help optimize the Android side of things.

For the Android code you'll need JSOUP from http://jsoup.org/download
and to add it to your Eclipse project you'll need to:

Download the library to your host development system.
Create a new folder, libs, in your Eclipse/Android project.
Right-click libs and choose Import -> General -> File System, then Next, Browse in the filesystem to find the library's parent directory (i.e.: where you downloaded it to).
Click OK, then click the directory name (not the checkbox) in the left pane, then check the relevant JAR in the right pane. This puts the library into your project (physically).
Right-click on your project, choose Build Path -> Configure Build Path, then click the Libraries tab, then Add JARs..., navigate to your new JAR in the libs directory and add it. (This, incidentally, is the moment at which your new JAR is converted for use on Android.)

Install instructions from: http://stackoverflow.com/questions/...to-an-eclipse-android-project/3643015#3643015

Arduino Code:

Code:
#include <WiServer.h>
#include <string.h>
#define WIRELESS_MODE_INFRA 1
#define WIRELESS_MODE_ADHOC 2
#define ledPin1 5  //extra pin
#define ledPin2 6  //pin wired to the garage door remote
#define ledPin3 9  //pin that turns off the red LED on the WiShield
// Wireless configuration parameters -----------
unsigned char local_ip[] = {192,168,1,225}; // IP address of WiShield
unsigned char gateway_ip[] = {192,168,1,1}; // router or gateway IP address
unsigned char subnet_mask[] = {255,255,255,0}; // subnet mask for the local network
char ssid[] = {"Linksys"}; // max 32 bytes
unsigned char security_type = 0; // 0 - open; 1 - WEP; 2 - WPA; 3 - WPA2
// WPA/WPA2 passphrase
const prog_char security_passphrase[] PROGMEM = {"password"};	
// max 64 characters
// WEP 128-bit keys
prog_uchar wep_keys[] PROGMEM = { 
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,	// Key 0
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// Key 1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// Key 2
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	// Key 3
};
// setup the wireless mode; infrastructure - 
//connect to AP; adhoc - connect to another WiFi device
#define WIRELESS_MODE_INFRA	1
#define WIRELESS_MODE_ADHOC	2
unsigned char wireless_mode = WIRELESS_MODE_INFRA;
unsigned char ssid_len;
unsigned char security_passphrase_len;
// End of wireless configuration parameters ------------------
boolean states[3]; //holds led states
char stateCounter; //used as a temporary variable
char tmpStrCat[100]; //used in processing the web page
char stateBuff[4]; //used in text processing around boolToString()
char numAsCharBuff[2];
char ledChange;
void boolToString (boolean test, char returnBuffer[4])
{
returnBuffer[0] = '\0';
if (test)
{
strcat(returnBuffer, "Open");
}
else
{
strcat(returnBuffer, "Closed");
}
}
void printStates()
{
for (stateCounter = 0 ; stateCounter < 3; stateCounter++)
{
boolToString(states[stateCounter], stateBuff);
Serial.print("State of ");
Serial.print(stateCounter);
Serial.print(": ");
Serial.println(stateBuff);
} 
}
void writeStates()
{
//set led states
digitalWrite(ledPin1, states[0]);
digitalWrite(ledPin2, states[1]);
digitalWrite(ledPin3, states[2]);
}
// This is our page serving function that generates web pages
boolean sendPage(char* URL) {
Serial.println("Page printing begun");
printStates();
writeStates();
//check whether we need to change the led state
if (URL[1] == '?' && URL[2] == 'L' && URL[3] == 'E' && URL[4] == 'D')
//url has a leading /
{
ledChange = (int)(URL[5] - 48); //get the led to change.
for (stateCounter = 0 ; stateCounter < 3; stateCounter++)
{
if (ledChange == stateCounter)
{
states[stateCounter] = !states[stateCounter];
Serial.print("Have changed ");
Serial.println(ledChange);
}
}
//after having change state, return the user to the index page.
WiServer.print("<HTML><HEAD><meta http-equiv='REFRESH' content='0;url=/'></HEAD></HTML>");
return true;
}
if (strcmp(URL, "/") == false) //why is this not true?
{
WiServer.print("<html><head><title>Door Opener</title></head>");
WiServer.print("<body><center>GARAGE DOOR OPENER<center>\n<center><BR><BR>");
for (stateCounter = 0; stateCounter < 3; stateCounter++) //for each led
{
numAsCharBuff[0] = (char)(stateCounter + 49); //as this is displayed use 1 - 3 rather than 0 - 2
numAsCharBuff[1] = '\0'; //strcat expects a string (array of chars) rather than a single character.
//This string is a character plus string terminator.
tmpStrCat[0] = '\0'; //initialise string
strcat(tmpStrCat, "<input type=\"submit\" onclick=\"location=\'/?LED \'\" value=\"Opener \""); //start the string
tmpStrCat[45] = (char)(stateCounter + 48); //add the led number
tmpStrCat[63] = (char)(stateCounter + 49);
tmpStrCat[66] = '\0'; //terminate the string properly for later.
strcat(tmpStrCat, ">");
boolToString(states[stateCounter], stateBuff);
strcat(tmpStrCat, "Door ");
strcat(tmpStrCat, stateBuff);
strcat(tmpStrCat, "<br>");
//strcat(tmpStrCat, "</a> "); 
//we now have something in the range of <a href=?LED0>Led 0: Off</a>
WiServer.print(tmpStrCat);
}
WiServer.print("</html> ");
return true;
}
}
void setup() {
// Initialize WiServer and have it use the sendMyPage function to serve pages
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(ledPin3, OUTPUT);
Serial.begin(9600);
WiServer.init(sendPage);
states[0] = false;
states[1] = false;
states[2] = false;
}
void loop(){
// Run WiServer
WiServer.server_task();
delay(10);
}

**EDIT: Updated Android code.**

To do: add logic / automate closing of the arduino circuit

Right now it works like this:
-------------------------------------------------------------------
Door | Circuit
closed | off -- default: door closed circuit off
open | on -- button pushed 1st time: door open circuit on
open | off -- button pushed 2nd time: door open circuit off
closed | on -- button pushed 3rd time: door closed circuit on
closed | off -- button pushed 4th time: door closed circuit off
I think it should work like this:

---------------------------------------------------------------------
Door | Circuit
closed | off -- default: door closed circuit off
open | on -- button pushed 1st time: door open circuit on
open | off -- after a set time app automatically closes circuit
closed | on -- button pushed 2nd time: door closed circuit on
closed | off -- after a set time app automatically closes circuit

Android Code:
Code:
package com.garagedoor.opener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URI;

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

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class GarageDoorOpenerActivity extends Activity {
	
        //external ip holder
	public String publicIP = "";
        //whatever your arduino ip address was set to holder
	public String localIP = "";	
	public String readURL = "";
	public String portNumber = "";
	public String readpublicIP = "";
	public String readlocalIP = "";
	public String readportNumber = "";
	public String URL = "";
	public String garagestate = "";
	public String pin = "";
	public String pinName = "";
	public String networkName = "";
	
	public int pinCheck = 0;
	boolean useExternal;
	private static final int REQUEST_CODE = 100;
	public String customURL[] = {"http://","/"};
	private AsyncTask<?, ?, ?> mTask;
	private ProgressDialog dialog = null;
	boolean viewLocal = true;
	boolean viewPublic = true;
	boolean viewPort = true;
	boolean viewPin = true;
	int buttondDefault = R.drawable.buttondefault;
	int doorClosed = R.drawable.doorclosed;
	int doorOpen = R.drawable.dooropen;
	int option1On = R.drawable.option1on;
	int option1Off = R.drawable.option1off;
	int arduinoOn = R.drawable.arduinoon;
	int arduinoOff = R.drawable.arduinooff;
	int option1default = R.drawable.option1default;
	int doorDefault = R.drawable.doordefault;
	int arduinoDefault = R.drawable.arduinodefault;
	
	int saved_button = R.drawable.buttondefault;
	
	public String data = null;
	String publicIPpart1 = "";
	String publicIPpart2 = "";
	String publicIPpart3 = "";
    HttpResponse responseGet = null;

	 @Override
	    public void onCreate(Bundle savedInstanceState) {
	        super.onCreate(savedInstanceState);
	        setContentView(R.layout.main);
	        
	        SharedPreferences settings = getSharedPreferences("app_settings", 0);
	        publicIP = settings.getString("public_ip", publicIP);
			localIP = settings.getString("local_ip",localIP);
			useExternal = settings.getBoolean("use_external", useExternal);
			pin = settings.getString("arduino_pin",pin);
			portNumber = settings.getString("port_number", portNumber);
			URL = settings.getString("passed_url", URL);
			publicIPpart1 = settings.getString("publicIP_part1", publicIPpart1);
			publicIPpart3 = settings.getString("publicIP_part3", publicIPpart3);
			pinName = settings.getString("pin_name", pinName);
			networkName = settings.getString("network_name", networkName);
			pinCheck = settings.getInt("pin_check",pinCheck);
			
			saved_button = settings.getInt("saved_button",saved_button);
			findViewById(R.id.button1).setBackgroundResource(saved_button);	
			
	        EditText displayInternal = (EditText) findViewById(R.id.displayInternal);
	        EditText displayExternal = (EditText) findViewById(R.id.displayExternal);
	        EditText displayPort = (EditText) findViewById(R.id.displayPort);
	        displayInternal.setText(localIP);
	        displayExternal.setText(publicIPpart1);
	        displayPort.setText(publicIPpart3);
	        EditText displayPin = (EditText) findViewById(R.id.displayPin);
	        displayPin.setText(pinName);
	        EditText displayNetwork = (EditText) findViewById(R.id.displayNetwork);
	        
	        if(networkName == "External"){
				URL = publicIP;
			}
			if(networkName == "Local"){
				URL = localIP;
			}
	        
	        displayNetwork.setText(networkName);
	        	        
	        final Button button = (Button) findViewById(R.id.button1);
	        button.setOnClickListener(new View.OnClickListener() {
	            public void onClick(View v) {
	              // Perform action on click
		        	mTask = new httpTask().execute();
		    		}
	        });
	    }
//OPTIONS MENU INFLATER - FILLS THE OPTIONS MENU
	public boolean onCreateOptionsMenu(Menu menu) {
	    MenuInflater inflater = getMenuInflater();
	    inflater.inflate(R.menu.menu, menu);
	    return true;
	}
//OPTIONS MENU
	public boolean onOptionsItemSelected(MenuItem item) {
        EditText displayPin = (EditText) findViewById(R.id.displayPin);
        EditText displayNetwork = (EditText) findViewById(R.id.displayNetwork);
        EditText displayInternal = (EditText) findViewById(R.id.displayInternal);
        EditText displayExternal = (EditText) findViewById(R.id.displayExternal);
        EditText displayPort = (EditText) findViewById(R.id.displayPort);
	    switch (item.getItemId()) {
	    		case R.id.save:
	    			Toast.makeText(getBaseContext(), "Settings saved.", Toast.LENGTH_SHORT).show();
		    		save();
		    		break;
	    		case R.id.pins:
	    			break;
	    			case R.id.pin1:
	    				pin = "?LED0";
	    				pinCheck = 1;
	    		        pinName = "Option 1";
	    		        displayPin.setText(pinName);
	    		        findViewById(R.id.button1).setBackgroundResource(R.drawable.option1default);
	    				saved_button = R.drawable.option1default;
	    		        save();
	    				break;
	    			case R.id.pin2:
	    				pin = "?LED1";
	    				pinCheck = 2;
	    		        pinName = "Garage Door";
	    		        displayPin.setText(pinName);
	    		        findViewById(R.id.button1).setBackgroundResource(R.drawable.doordefault);
	    		        saved_button = R.drawable.doordefault;
	    		        save();
	    				break;
	    			case R.id.pin3:
	    				pin = "?LED2";
	    				pinCheck = 3;
	    				pinName = "Arduino LED";
	    		        displayPin.setText(pinName);
	    		        findViewById(R.id.button1).setBackgroundResource(R.drawable.arduinodefault);
	    		        saved_button = R.drawable.arduinodefault;
	    		        save();
	    				break;
		    	case R.id.useExternal:
	    			if(useExternal == false){
	    				URL = localIP;
	    				useExternal = true;
	    				networkName = "Local";
	    				displayNetwork.setText(networkName);
	    				save();
	    				break;
	    			}
	    			else if(useExternal == true){
	    				URL = publicIP;
	    				useExternal = false;
	    				networkName = "External";
	    				displayNetwork.setText(networkName);
	    				save();
	    				break;
	    			}else {
	    			break;
	    			}
	    		case R.id.inputIP:
	    			enterIP();
	    			break;
	    		case R.id.clear:
	    			publicIP = "";
	    			readURL = "";
	    			portNumber = "";
	    			readpublicIP = "";
	    			readlocalIP = "";
	    			readportNumber = "";
	    			URL = "";
	    			garagestate = "";
	    			pin = "";
	    			publicIPpart2 = "";
	    			networkName = "";
	    			pinName = "";
	    			localIP = "";	
	    			publicIPpart1 = "";
	    			publicIPpart3 = "";
    				displayNetwork.setText(networkName);
    		        displayPin.setText(pinName);
    		        displayInternal.setText(localIP);
    		        displayExternal.setText(publicIPpart1);
    		        displayPort.setText(publicIPpart3);
    		        findViewById(R.id.button1).setBackgroundResource(R.drawable.buttondefault);
    		        saved_button = R.drawable.buttondefault;
	    			save();
	    			break;	    			
	    }
	    return true;
	}
//Http Task
	private class httpTask extends AsyncTask<Void, Void, Void> {
    HttpEntity resEntityGet = null;

		@Override
		protected void onPreExecute() {
		    GetMethod test = new GetMethod();
	  	    String returned;
			try {
				returned = test.getInternetData();
				if (pinCheck == 1){
					//Toast.makeText(getBaseContext(), "pinCheck = 1.", Toast.LENGTH_SHORT).show();
			 		if(returned.toString().contains("\"Opener 1\">Door Closed")){  //"\"Opener 1\">Door Closed"
						//Toast.makeText(getBaseContext(), "Option 1 on.", Toast.LENGTH_SHORT).show();
						findViewById(R.id.button1).setBackgroundResource(R.drawable.option1on);
					}
					if(returned.toString().contains("\"Opener 1\">Door Open")){
						//Toast.makeText(getBaseContext(), "Option 1 off.", Toast.LENGTH_SHORT).show();
						findViewById(R.id.button1).setBackgroundResource(R.drawable.option1off);		    		
					}
					}
					if (pinCheck == 2){
			    	//Toast.makeText(getBaseContext(), "pinCheck = 2.", Toast.LENGTH_SHORT).show();
					if(returned.toString().contains("\"Opener 2\">Door Closed")){  //"\"Opener 2\">Door Closed"
						//Toast.makeText(getBaseContext(), "Opening the door.", Toast.LENGTH_SHORT).show();
						findViewById(R.id.button1).setBackgroundResource(R.drawable.dooropen);		    		
					}
					if(returned.toString().contains("\"Opener 2\">Door Open")){
						//Toast.makeText(getBaseContext(), "Closing the door.", Toast.LENGTH_SHORT).show();
						findViewById(R.id.button1).setBackgroundResource(R.drawable.doorclosed);		    		
					}
					} 
					if (pinCheck == 3){
			    	//Toast.makeText(getBaseContext(), "pinCheck = 3.", Toast.LENGTH_SHORT).show();
					if(returned.toString().contains("\"Opener 3\">Door Closed")){  //"\"Opener 3\">Door Closed"
						//Toast.makeText(getBaseContext(), "Turning on the LED.", Toast.LENGTH_SHORT).show();
						findViewById(R.id.button1).setBackgroundResource(R.drawable.arduinoon);		    		
					}
					if(returned.toString().contains("\"Opener 3\">Door Open")){
						//Toast.makeText(getBaseContext(), "Turning off the LED.", Toast.LENGTH_SHORT).show();
						findViewById(R.id.button1).setBackgroundResource(R.drawable.arduinooff);		    		
					}
					}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			dialog = new ProgressDialog(GarageDoorOpenerActivity.this);
			dialog.setMessage("Working");
			dialog.show();
		}
		@Override
		protected Void doInBackground(Void... params) {
		  try {
        HttpClient client = new DefaultHttpClient();
        HttpGet get = new HttpGet(customURL[0] + URL + customURL[1] + pin);
        responseGet = client.execute(get);  
        resEntityGet = responseGet.getEntity();
      } catch (Exception e) {
          e.printStackTrace();
      }
		return null;
		}
		@Override
		protected void onPostExecute(Void params) {
			if(dialog.isShowing())
				dialog.dismiss();
        if (resEntityGet != null) {  
        	Toast.makeText(getBaseContext(), "Done. ", Toast.LENGTH_SHORT).show();
        	resEntityGet = null;
        }
		}
	}
    public class GetMethod {
    	public String getInternetData() throws Exception{
    		BufferedReader in = null;
    		String data = null;
    		try{
    			HttpClient client = new DefaultHttpClient();
    			URI url = new URI(customURL[0] + URL + customURL[1]); //customURL[0] + URL + customURL[1]
    			HttpGet request = new HttpGet();
    			request.setURI(url);
    			HttpResponse response = client.execute(request);
    			in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
    			StringBuffer sb = new StringBuffer("");
    			String l = "";
    			String nl = System.getProperty("line.separator");
    			while ((l = in.readLine()) !=null){
    				sb.append(l + nl);				
    			}
    			in.close();
    			data = sb.toString();
    			return data;
    		} finally{
    			if (in !=null){
    				try{
    					in.close();
    					return data;
    				} catch (Exception e){
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    } 
//Local / Public IP Address Entry
	public void enterIP(){
        Intent j = new Intent(this, enterIP.class);
        j.putExtra("public_ip", publicIP);
        j.putExtra("local_ip", localIP);
        j.putExtra("port_number", portNumber);
		startActivityForResult(j, REQUEST_CODE);
	}
//Activity Result
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) {
			if (data.hasExtra("public_ip")){
				readpublicIP = data.getExtras().getString("public_ip");
				publicIPpart1 = String.valueOf(readpublicIP);
			}
			if (data.hasExtra("local_ip")){
				readlocalIP = data.getExtras().getString("local_ip");
				localIP = String.valueOf(readlocalIP);
			}
			if (data.hasExtra("port_number")){
				readportNumber = data.getExtras().getString("port_number");	
				publicIPpart3 = String.valueOf(readportNumber);
			}
				publicIPpart2 = ":";
				publicIP = (publicIPpart1 + publicIPpart2 + publicIPpart3);
			}
		EditText displayInternal = (EditText) findViewById(R.id.displayInternal);
        EditText displayExternal = (EditText) findViewById(R.id.displayExternal);
        EditText displayPort = (EditText) findViewById(R.id.displayPort);
        displayInternal.setText(localIP);
        displayExternal.setText(publicIPpart1);
        displayPort.setText(publicIPpart3);
		save();
		}
//SAVE FUNCTION
	private void save() {
		SharedPreferences settings = getSharedPreferences("app_settings", 0);  
		SharedPreferences.Editor prefEditor = settings.edit();
		prefEditor.putString("publicIP_part1", publicIPpart1);
		prefEditor.putString("publicIP_part3", publicIPpart3);
		prefEditor.putString("public_ip", publicIP);
		prefEditor.putString("local_ip",localIP);
		prefEditor.putBoolean("use_external", useExternal);
		prefEditor.putString("arduino_pin",pin);
		prefEditor.putString("port_number", portNumber);
		prefEditor.putString("passed_url", URL);
		prefEditor.putString("pin_name", pinName);
		prefEditor.putString("network_name", networkName);
		prefEditor.putInt("pin_check",pinCheck);
		prefEditor.putInt("saved_button",saved_button);
		prefEditor.commit();				
	}
//On Pause
	@Override
	protected void onPause() {
		super.onPause();
		if(dialog != null && dialog.isShowing())
			dialog.dismiss();
		if(mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING)
			mTask.cancel(true);
	}
}

enterIP class:
Code:
package com.garagedoor.opener;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class enterIP extends Activity {
	String publicIP = "";
	String localIP = "";
	String portNumber = "";
	private EditText publicIpText;
	private EditText localIpText;
	private EditText portNumberText;
	
	 @Override
		protected void onCreate(final Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
			setContentView(R.layout.enterip);

			//Button to set the user's upc code
			final Button button1 = (Button) findViewById(R.id.savebutton);
			   button1.setOnClickListener(new OnClickListener() {
			         public void onClick(View v) {
			        	 
			        	localIpText = (EditText) findViewById(R.id.editText1);
			        	localIP = localIpText.getText().toString();
			        	
			        	publicIpText = (EditText) findViewById(R.id.editText2);
			        	publicIP = publicIpText.getText().toString();
			        	
			        	portNumberText = (EditText) findViewById(R.id.editText3);
			        	portNumber = portNumberText.getText().toString();
			     		finish();
			        } 
			  });
	    }
		public void finish() {
			//Returns the user's code back to the main app
				Intent data = new Intent();
				// Return some hard-coded values
				data.putExtra("public_ip", publicIP);
				data.putExtra("local_ip", localIP);
				data.putExtra("port_number", portNumber);
				setResult(RESULT_OK, data);
				//Finish is what is called whenever you hit Back on your phone
				super.finish();
			}		
	}
enterIP allows the user input their IP addresses for local and external. The app takes the IP addresses and adds http:// to the beginning and / to the end. The menu option about the LEDs adds ?LED0 ?LED1 or ?LED2 to the end of the / that was added to the end of the URL. If the ip being used is on the external network a port number that was provided is added after the IP address before the / (8080 is what is port forwarded on the router as port 80 doesn't work with my service provider)

So when you configure everything and press the button the app sends either:

http://192.168.1.100/?LED2 or http://74.125.224.72/?LED2 depending on if you're on the local network or not.

Video of the Arduino side of things:

http://www.youtube.com/watch?v=XKPXZB3v7dU

Any help anyone can provide would be great. Thanks.
 
Upvote 0

BEST TECH IN 2023

We've been tracking upcoming products and ranking the best tech since 2007. Thanks for trusting our opinion: we get rewarded through affiliate links that earn us a commission and we invite you to learn more about us.

Smartphones