Home Automation with Android and Arduino Yún

The Arduino Yún is a WLAN capable development board featuring an ATMega microcontroller, as well as a separate chip running a small Linux distribution, making it a perfect candidate for home automation projects like in the picture below! This basic tutorial will show you how to communicate wirelessly between your Arduino Yún and an Android device. Schematics and components for dimming a high power led are also available at the end of this post.

Dimming a high power led wirelessly from an Android device
Dimming a high power led wirelessly from an Android device

Arduino part

To keep things simple, we will begin by using the official Bridge library example sketch from here. After this sketch is installed, you can control the Arduino’s pins by entering specific URLs in a web browser. You need to set REST API access to open in the Arduino Yún configuration webinterface in order for this to work.

For instance (assuming your Arduino’s IP address is 192.168.1.33)

  • http://192.168.1.33/arduino/digital/13/1 will issue a digitalWrite(13,1). And since pin 13 is connected to the on-board LED, the LED is lit up.
  • http://192.168.1.33/arduino/digital/13/0 will call digitalWrite(13,0), and thus disable the LED.
  • http://192.168.1.33/arduino/analog/13/128 results in analogWrite(13,128), which will dim the on-board LED to about 50% intensity. In the following Android application, we will use this URL to dim the LED accordingly.

On the other hand, you can read the state of the Arduino’s pins.

  • http://192.168.1.33/data/get/D13 will return a JSON string, which can be parsed to get the appropriate value.

Actually, entering the above URL will not directly read pin 13. It will simply try to return a key/value pair in the datastore with key = D13. By studying the Arduino sketch, you can see that there are various occurences of Bridge.put(key, String(value)). This is used to update the datastore on the Linux environment.

Using formatted URLs in this way is also known as Representational state transfer (REST).

Android code

The Android part is rather straight forward. We will use the above URLs to write and read values on the Arduino. Some care must be taken since this involves networking. Therefore we must use separate threads, but we’ll get to that later. Let’s start a new Android project by adding a SeekBar and a TextView to our main layout.

<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=".MainActivity" >

    <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="255" />

    <TextView
        android:id="@+id/value"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="0" />

</RelativeLayout>

The SeekBar slider will be used to set the brightness of the on-board LED. The current value is read back from the Arduino and displayed in our TextView. Since calling the URLs will be done in a different thread, we need some form of inter thread communication. Synchronized, wait and notify come to mind, but there are – at least in my opinion – easier to grasp mechanisms. For instance an ArrayBlockingQueue which is basically a FIFO queue that can safely be filled and emptied from multiple threads. So let’s create an ArrayBlockingQueue and fill it with values whenever the SeekBar slider is moved.

private ArrayBlockingQueue<Integer> mQueue = new ArrayBlockingQueue<Integer>(100);

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

	mSeekBar = (SeekBar) findViewById(R.id.seekBar);
	mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
		@Override
		public void onStopTrackingTouch(SeekBar seekBar) {}
		@Override
		public void onStartTrackingTouch(SeekBar seekBar) {}
		@Override
		public void onProgressChanged(SeekBar seekBar, int progress,
				boolean fromUser) {
			mQueue.offer(progress);
		}
	});
}

For networking, we will use two separate threads, one for sending values to the Arduino and one for reading values from the Arduino. Here is the code for the sending thread. Full source code including both threads is available at the bottom of this post.

private static Thread sNetworkThreadSend = null;
private final Runnable mNetworkRunnableSend = new Runnable() {
	@Override
	public void run() {
		String urlBase = "http://"+ARDUINO_IP_ADDRESS+"/arduino/analog/13/";
		String url;
		try {
			while(!mStop.get()){
				int val = mQueue.take();
				if(val >= 0){
					HttpClient httpClient = new DefaultHttpClient();
					url = urlBase.concat(String.valueOf(val));
					HttpResponse response = httpClient.execute(new HttpGet(url));
				}
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		sNetworkThreadSend = null;
	}
};

Now we only need to start the threads and we’re golden. A good practice is to start network threads in the Activity’s onStart handler and stop them in the – you guessed right ;-) – onStop handler. After all, one usually doesn’t want to waste resources when the Activity is hidden anyways.

private AtomicBoolean mStop = new AtomicBoolean(false);

@Override
protected void onStart() {
	mStop.set(false);
	if(sNetworkThreadSend == null){
		sNetworkThreadSend = new Thread(mNetworkRunnableSend);
		sNetworkThreadSend.start();
	}
	if(sNetworkThreadReceive == null){
		sNetworkThreadReceive = new Thread(mNetworkRunnableReceive);
		sNetworkThreadReceive.start();
	}
	super.onStart();
}

@Override
protected void onStop() {
	mStop.set(true);
	mQueue.clear();
	if(sNetworkThreadSend != null) sNetworkThreadSend.interrupt();
	if(sNetworkThreadReceive != null) sNetworkThreadReceive.interrupt();
	super.onStop();
}

The full Android and Arduino Yún REST example can be downloaded from here.

It gets better…

The above example should be OK for many applications already, however, you will notice that it takes quite a while until the LED finally reaches its desired value. The reason for this is that the SeekBar’s onProgressChanged method is called many times when swiping the slider, and therefore our queue is filled much faster than the thread can handle. One quick fix is to clear the queue before adding a new element, like this:

@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
	mQueue.clear();
	mQueue.offer(progress);
}

However, it’s still not very responsive. Instead of issuing a new http request for every value to be transmitted, it would be way better if we had some kind of a continuous connection between the Arduino and the Android device. As you can see in the example Bridge sketch, there is a YunServer class. Normally this server listens on port 5555 where URLs in the type of http://arduino.ip/arduino/some/command are forwarded for easy REST access. But we can also use the YunServer to listen on another port! We may then connect to this port using a socket on the Android side, and we will be able to continuously send new values without the need to initiate a new http request. The key is to initiate the YunServer with a different constructor, and also configure it so that it will listen on connections other than localhost, like so:

#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>

#define PORT 6666
YunServer server(PORT);

void setup() {
  Serial.begin(115200);
  Bridge.begin();
  server.noListenOnLocalhost();
  server.begin();
}

You can then accept clients in the main loop

void loop() {
  YunClient client = server.accept();

  if(client.connected()){
    String question = "What is your name?\n";
    client.write((uint8_t*)&question[0], question.length());
    
    String response;
    while(client.connected()){
      if(client.available()){
        char cmd = client.read();
        if(cmd == '\n'){
          break;
        } else {
          response += String(cmd);
        }
      }
    }
    response = "Bye "+response+"\n";
    client.write((uint8_t*)&response[0], response.length());
    
    client.stop();
  }

  delay(1000);
}

Try the above code and then test it from the command line by entering (obviously adjust the IP address)

user@host:~$ netcat 192.168.1.47 6666

Pretty neat, right? :-)

For communicating with the Android device we will use a slightly different sketch, which you can download from here. The basic idea is, that we send the desired brightness value 0..255 in ASCII format from the Android device to the Arduino. Also, the new line symbol ‘\n’ is used to detect the end of a brightness value. To send those values, we need to adjust our network thread as follows:

private OutputStream mOutputStream = null;
private Socket mSocket = null;

private static Thread sNetworkThread = null;
private final Runnable mNetworkRunnable = new Runnable() {
	@Override
	public void run() {
		try {
			mSocket = new Socket(ARDUINO_IP_ADDRESS, PORT);
			mOutputStream = mSocket.getOutputStream();
		} catch (UnknownHostException e1) {
			e1.printStackTrace();
			mStop.set(true);
		} catch (IOException e1) {
			e1.printStackTrace();
			mStop.set(true);
		}

		mQueue.clear(); // we only want new values
			
		try {
			while(!mStop.get()){
				int val = mQueue.take();
				if(val >= 0){
					mOutputStream.write((val+"\n").getBytes());
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally{
			try {
				mStop.set(true);
				if(mOutputStream != null) mOutputStream.close();
				if(mSocket != null) mSocket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		sNetworkThread = null;
	}
};

The LED brightness should now adjust as smooth as butter. I have also tried to summarize the most important communication aspects of the whole application in the following diagram:

serverbox_android_arduino_yun

  1. The Arduino YunServer repeatedly accepts a client to connect
  2. In the network thread on the Android side, a socket is created connecting to the Arduino. Furthermore, an output stream on that socket is opened.
  3. Moving the SeekBar slider adds new values to our queue. This happens on the UI a.k.a main thread
  4. Within a loop in the network thread, values are taken from the queue and written to the acquired output stream.
  5. On the Arduino side, values are received by calling the read method on the client object

We hope this should give you a good starting point for your own Android/Arduino projects :-)

Resources:

High power led dimming circuit:
arduinoyun_android_led_schematic

  • We are using an led spot rated at 12V DC/AC such as this one. This component can be connected directly to a 12V power supply without the need for a current limiting resistor. If you use a standalone led, you will most likely need additional circuitry to limit the current flowing through the led.
  • An N-Channel Mosfet such as the RFP30N06LE is used to switch the led spot on and off. If the voltage at the gate is above 2V, a current is flowing from drain to source, and thus the led is on. If the voltage at the gate is 0V, no current can flow and the led is off. In the on-state, there will be a slight voltage drop across the Mosfet, so the total voltage across the led will not be the full 12V. However, this is usually not a problem, since the led will still work well with lower voltages (even with only 9V the led spot will shine brightly).
  • By connecting a PWM output to the Mosfet gate, it is possible to dim the led. What happens is that the led is turned on and off many times per second (default Arduino PWM frequency is around 500Hz).
  • Optionally a pull-down resistor could be connected between Gate and Source. This will make sure that the led is off when the Arduino is disconnected. It is also a good idea to mount a heatsink to the Mosfet.

Here are again all the source files for download.

Android and Arduino simple REST example:

Android and Arduino client/server example:

17 thoughts on “Home Automation with Android and Arduino Yún”

  1. hello … can you contact with me so I have many project need to programming with arduion… if you can work I can pay the cost of this projects . thanks

  2. Well, great work :)

    I had a problem when trying to use the app with the Yun through the Wifi as mentioned but the Yun didn’t respond at all although it worked well with the HTTP. Can you please help?

  3. Sir , i am doing an android home automation project ..i would like to know is it possible for android to communicate with raspberry pi(acting as server) which is connected to PIC controller (through wi-fi) which is in turn connected to a devices.

  4. Hi,
    Could you post the apk of the two examples. so I can install them on my android Phone. I am not so good in eclipse/java.
    THX

  5. Awesome write up and tutorial! And thank you for the code as well.

    Quick question, when I upload the arduino sketch and go to the URL to test: http://YUN IP]/arduino/analog/13/
    I get an error: Could not connect to YunServer 146 Connection refused

    However, if i upload the Bridge Example (Examples–>Bridge–>Bridge) and try the URL, i get this: Pin A13 reads analog 1023

    Is there something in your sketch that could be causing this?

    1. Hi Jerah

      Thanks a lot :-)

      I am not entirely sure which sketch you are referring to, but anyways, the REST-like interface (http://arduino_ip/arduino/analog/xx or http://arduino_ip/arduino/digital/xx etc.) is only available if you install the mentioned Bridge example sketch from the arduino.cc website (which should be the same as the one under Examples, Bridge, Bridge in the Arduino IDE). Have a look at the function process() and especially:

      String command = client.readStringUntil('/');
      

      to figure out how the interface works.

      Best Regards
      andreas

  6. Can you please post the apk file for the Android application. Becouse I can’t produce my own applications.
    Thanks

    Btw… Very nice tutotial!

    1. Hi Job

      Sorry for not replying earlier. Posting the APK does not really make a lot of sense, since the Arduino’s IP address is hardcoded in the source code. The reason for this is that you probably want to be connected to your Wifi with your Android smartphone, so that you can use the internet as is, and also have the Arduino in the same Wifi network. Depending on your Wifi router, the IP address is different of course (a better approach would be to let the user enter the Arduino’s IP address within the Android application).

      Nevertheless, I uploaded an APK which assumes the Android device is connected to the default Arduino Yun access point, in which case the IP address is 192.168.240.1

      By the way, creating an APK really is not that hard:

      • Download ADT-Bundle
      • Unzip and start Eclipse
      • File -> Import
      • Android -> Existing Android Code Into Workspace
      • Browse for the directory where you downloaded the above application source code, and create the project
      • If you have a device connected via USB, select Run -> Run
      • Depending on your operating system, you may need to install drivers for the USB connection to work. Also make sure, you have ADB debugging enabled on your Android device.

      Best Regards
      Andreas

  7. Hi Andreas,

    nice code!! I am doing something similar as the last (socket style) code you explained.
    In my project however I also want to write some data back to the android device, but I can’t get it working.I can write to the arduino, and than send a reply, but I want to be able to write and read at both sides, at any time.
    Any suggestions?

    regards,
    Wouter

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>