Hardware components | ||||||
![]() |
| × | 1 | |||
| × | 1 | ||||
| × | 1 |
In this project I used a Particle Photon to control my garage door via an Android App. The app has a button on screen that you press to open and close the door. It also checks the status of the door so you know if it is open or closed.
This is my first project with the Particle Photon. The Photon is super easy to use and I was able to find a lot of good tutorials online.
However I couldn't find any good tutorials regarding integrating it with an Android App. So I decided to post my code.
I used a simple relay to control the door. Most garage door openers have 2 wires and by pressing the button you just short the wires together. Disclaimer - This worked on my door but I can't guarantee it will work on all doors. Test your door with a multi-meter to make sure it is just shorting the 2 wires together. I just spliced into the wiring running to the door switch.
For checking the door status I used a magnetic reed switch with a magnet on the door. However you can use any sensor you want.
The code for the Photon and Android App are listed below. The only thing I will probably change in the future is putting a timeout in the Android app so if the app can't communicate to the Photon it will simply timeout instead of eventually crashing the app as it does now.
// Set-up variables, Pin D1 will control the door relay and Pin D4 will check whether the door is open or closed
int door = D1;
int status = D4;
int statusvalue;
void setup()
{
// Sets the door relay pin as an output and the status pin as an input
pinMode(door, OUTPUT);
pinMode(status, INPUT);
// This sets up a Spark function that will recieve the open/close command from the Spark Cloud.
Spark.function("led",doorToggle);
// This sets the initail condition of the relay. It is off by default.
digitalWrite(door, LOW);
// This sends the door status open/closed to the Spark Cloud.
Spark.variable("status", &statusvalue, INT);
}
void loop()
{
// Constantly checks the status of the door (open or closed).
statusvalue = digitalRead(status);
}
// This gets called if the Spark Cloud commands a door open/close
int doorToggle(String command) {
// If the command is "on" the relay closes for 1 second and then opens again.
// You may have to adjust the delay depending on your garage door opener.
if (command=="on") {
digitalWrite(door,HIGH);
delay(1000);
digitalWrite(door,LOW);
return 1;
}
else if (command=="off") {
digitalWrite(door,LOW);
return 0;
}
else {
return -1;
}
}
Android App - Main Activity
Javapackage com.example.garagebot;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.Bundle;
import android.app.Activity;
import android.view.View.OnClickListener;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.util.Log;
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.TabHost;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener{
public Button mTrigger, mRefresh;
public String savedstatus, statusString;
public Integer status;
// Progress Dialog
public ProgressDialog Dialog;
// JSON parser class
JSONParser jsonParser = new JSONParser();
//Communication to Spark Cloud.
//Type in your Photon ID where it says Your Photon Id below.
//Type in your Acess Token where is says Your Access Token below.
private static final String Trigger = "https://api.particle.io/v1/devices/Your Photon Id/led?access_token=Your Access Token" ;
private static final String StatusCheck = "https://api.particle.io/v1/devices/Your Photon Id/status?access_token=Your Access Token" ;
//JSON element ids from response of php script:
private static final String TAG_SUCCESS = "return_value";
private static final String TAG_RESULT = "result";
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//setup input fields
//setup buttons
mTrigger = (Button)findViewById(R.id.trigger);
mRefresh = (Button)findViewById(R.id.refresh);
//register listeners
mTrigger.setOnClickListener(this);
mRefresh.setOnClickListener(this);
new CheckStatus().execute();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
//When the Open/Close button is pressed the Trigger function is executed.
case R.id.trigger:
new Trigger().execute();
break;
//When the Refresh button is pressed the CheckStatus function is executed.
case R.id.refresh:
new CheckStatus().execute();
}
}
//The Trigger function opens and closes the door.
protected class Trigger extends AsyncTask<String, String, String> {
boolean failure = false;
//Pops up a dialog box saying the the door is opening or closing.
@Override
protected void onPreExecute(){
super.onPreExecute();
Dialog = new ProgressDialog(MainActivity.this);
Dialog.setMessage("Opening/Closing...");
Dialog.setIndeterminate(false);
Dialog.setCancelable(true);
Dialog.show();
}
//The network call is done on a background thread.
@Override
protected String doInBackground(String... args) {
try {
//Sets up the parameters to send to the Spark Cloud.
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("args", "on"));
//Calls the JSON parser which sends a POST to the Spark Cloud.
JSONObject json = jsonParser.makeHttpRequest(Trigger, "POST", params);
//Diagnostic message that dumps the JSON data to Logcat.
Log.d("Login attempt", json.toString());
//Checks whether the request was successful.
int success = json.getInt(TAG_SUCCESS);
} catch (JSONException e) {
e.printStackTrace();
}
//This is a delay to give the door time to open or close before you check the status.
//This will have to be adjusted depending on your door.
try {
Thread.sleep(12000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
//Dismisses the dialog box and checks the status of the door.
protected void onPostExecute(String file_url) {
Dialog.dismiss();
new CheckStatus().execute();
}
}
//This function checks whether the door is up or down.
protected class CheckStatus extends AsyncTask<String, String, String> {
boolean failure = false;
//Pops up a dialog box saying the the door status is being checked.
@Override
protected void onPreExecute(){
super.onPreExecute();
Dialog = new ProgressDialog(MainActivity.this);
Dialog.setMessage("Checking Door Status...");
Dialog.setIndeterminate(false);
Dialog.setCancelable(true);
Dialog.show();
}
//The network call is done in a background thread.
@Override
protected String doInBackground(String... args) {
try {
List<NameValuePair> params = new ArrayList<NameValuePair>();
//Sends a GET request to the Spark Cloud to retrieve the door status.
JSONObject json = jsonParser.makeHttpRequest(StatusCheck, "GET", params);
//Diagnostic message that dumps the JSON data to Logcat.
Log.d("Login attempt", json.toString());
//Gets the status from the JSON data.
status = json.getInt(TAG_RESULT);
//Diagnotics to see what the status value is.
Log.d("Status", String.valueOf(status));
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
//Dismisses the dialog box and displays whether the door is open or closed.
protected void onPostExecute(String file_url) {
Dialog.dismiss();
if (status == 0){
TextView text = (TextView) findViewById(R.id.status);
text.setText("Close");
}else{
TextView text = (TextView) findViewById(R.id.status);
text.setText("Open");
}
}
}
}
<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.garagebot.MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/trigger"
android:layout_centerHorizontal="true"
android:layout_marginTop="35dp"
android:text="Door Status"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView1"
android:layout_centerHorizontal="true"
android:text="Open/Close"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:id="@+id/trigger"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginTop="35dp"
android:onClick="Trigger"
android:text="Open/Close" />
<Button
android:id="@+id/refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/status"
android:layout_centerHorizontal="true"
android:text="Refresh" />
</RelativeLayout>
package com.example.garagebot;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;
public class JSONParser {
static InputStream is = null;
static JSONObject jObj = null;
static String json = "";
static Integer timeoutConnection = 10000;
static Integer timeoutSocket = 20000;
// constructor
public JSONParser() {
}
public JSONObject getJSONFromUrl(final String url) {
// Making HTTP request
try {
HttpPost httpPost = new HttpPost(url);
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
Log.d("jsonparser", "Timeout");
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
json = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
// try parse the string to a JSON object
try {
jObj = new JSONObject(json);
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
// return JSON String
return jObj;
}
// function get json from url
// by making HTTP POST or GET method
public JSONObject makeHttpRequest(String url, String method, List<NameValuePair> params) {
// Making HTTP request
try {
// check for request method
if(method == "POST"){
// request method is POST
// defaultHttpClient
HttpPost httpPost = new HttpPost(url);
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
httpPost.setEntity(new UrlEncodedFormEntity(params));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
}else if(method == "GET"){
// request method is GET
HttpGet httpGet = new HttpGet(url);
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
String paramString = URLEncodedUtils.format(params, "utf-8");
url += "?" + paramString;
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
Log.d("jsonparser", "timeout");
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
json = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
// try parse the string to a JSON object
try {
jObj = new JSONObject(json);
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
// return JSON String
return jObj;
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.garagebot"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Comments