DevOps Zone is brought to you in partnership with:

SysAdmin / Operations guy at DataSift managing the various elements of DataSift.com. Casual programmer in my spare time usually working with LAMP or Android (Java) but I also work with C++, Arduino and even embedded C on occasion (see blog for examples). In the past I've ran network cabling, managed the IT for a small business, been part of the SysAdmin team for a data center and managed a team of 10 SysAdmins at a managed hosting company that covered 4 data centers in 3 countries. Gareth is a DZone MVB and is not an employee of DZone and has posted 7 posts at DZone. You can read more from them at their website. View Full User Profile

Dabbling in Home Automation

01.08.2013
| 2912 views |
  • submit to reddit

A Swedish colleague of mine once told me that Clas Ohslon is termed a “husband kindergarten” by Swedish woman and I have to admit that if I’m ever nearby I do pop in because you never know when you might need a spare chainsaw chain, an extra flash drive or a spare part of your boat.

Anyhow during my latest jaunt I found that they’d started stocking home automation kit and were offering £10 off for every £50 spent. £100 (well £80) later I left with a variety of gadgets and not a clue what I was going to do with them.

For command and control I bought a Tellstick USB which was plugged into the NAS storage server (auto media archiving + uPNP / SMB for RaspBMC), for the ceiling lights I’d bought a bunch of NEXA LWNR 210′s which allow you to control the lights using the 300Mhz wireless comms or overriding with the existing switch, for sockets I used a combination of NEXA LMCR 1000′s and NEXA EYCR 2300′s (UK socket versions obviously).

After wiring up a good 50% of them I realised that I’d left the power on which I have to admit is a legacy of working on DataCenter power where uptime was more important than health and safety (ahh those were the days). Cue a quick trip to the Fuse box to prevent getting told off by the wife should I end up getting electrocuted.

Once everything was wired up and no fuses blown it was time to start automating!

As I was being lazy I opted to use the centralised “Telldus Live” product http://live.telldus.com/) rather than working out how to talk natively to the USB (although Telldus do support that) and quickly hacked together an Android widget (we use a Motorola Xoom with a dock as our XBMC / lighting / everything controller) and a PHP proxy to do the OAUTH comms with Telldus live;

The Android widget is very simple;

package net.networksaremadeofstring.zeus;
 
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;
 
public class ZeusTallLampWidget extends AppWidgetProvider 
{
  int N = 0;
	public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) 
	{
		N = appWidgetIds.length;
        for (int i=0; i<N; i++) 
        {
            int appWidgetId = appWidgetIds[i];
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget2);
            
            
            views.setTextViewText(R.id.textView1, "Tall Lamp");
            
            Intent offIntent = new Intent(context, ZeusTallLampWidget.class);
            offIntent.putExtra("id", 197068);
            offIntent.putExtra("type", false);
            PendingIntent pendingOffIntent = PendingIntent.getBroadcast(context, 0, offIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            views.setOnClickPendingIntent(R.id.button1, pendingOffIntent);
            appWidgetManager.partiallyUpdateAppWidget(appWidgetId, views);
            
            Intent onIntent = new Intent(context, ZeusTallLampWidget.class);
            onIntent.putExtra("id", 197068);
            onIntent.putExtra("type", true);
            PendingIntent pendingOnIntent = PendingIntent.getBroadcast(context, 1, onIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            views.setOnClickPendingIntent(R.id.button2, pendingOnIntent);
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
	}
	
	@Override
	public void onReceive(Context context, Intent intent) 
	{
		super.onReceive(context, intent);
 
	    if (intent.getIntExtra("id", 0) != 0)
	    {
	    	API.switchSomething(intent.getIntExtra("id", 0),intent.getBooleanExtra("type", false));
	    }
	}
}

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="32dp"
    android:minHeight="32dp"
    android:updatePeriodMillis="86400000"
    android:initialLayout="@layout/widget2"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen|keyguard">
</appwidget-provider>

<receiver android:name="net.networksaremadeofstring.zeus.ZeusHalogenWidget" android:label="Zeus Halogen Widget">
  <intent-filter>
    <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
	</intent-filter>
	<meta-data android:name="android.appwidget.provider" android:resource="@xml/widget" />
</receiver>

The switchsomething function is equally simple:

public static void switchSomething(final int ID, final boolean toggle)
  {
		((Thread) new Thread()
    	{
			public void run()
			{
				try
				{
					DefaultHttpClient client = new DefaultHttpClient(); 
					HttpParams params = new BasicHttpParams();
			        SchemeRegistry registry = new SchemeRegistry();
			        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
			        ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(params, registry);
			        
			        DefaultHttpClient httpclient = new DefaultHttpClient(mgr, client.getParams());
			    	HttpGet request = null;
			    	
			    	if(toggle)
			    	{
			    		Log.i("switchSomething","On");
			    		request = new HttpGet("http://fictional.tld/telldus/on.php?deviceid=" + Integer.toString(ID));
			    	}
			    	else
			    	{
			    		Log.i("switchSomething","Off");
			    		request = new HttpGet("http://fictional.tld/off.php?deviceid=" + Integer.toString(ID));
			    	}
			        
			        HttpResponse response = httpclient.execute(request);
			        
			        String rawJSON = EntityUtils.toString(response.getEntity());
			        response.getEntity().consumeContent();
					JSONObject TagObject = new JSONObject(rawJSON);
					
					Log.i("JSON",TagObject.toString(3));
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
    		}
    	}).start();
	}

Which in turn calls:

<?php
	require_once 'common.php';
	$DEVICEID = $_GET['deviceid'];
	$consumer = new HTTP_OAuth_Consumer(constant('PUBLIC_KEY'), constant('PRIVATE_KEY'), 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX');
	$params = array(
		'supportedMethods' => constant('TELLSTICK_TURNON') | constant('TELLSTICK_TURNOFF'),
		'id' => $DEVICEID,
		'response' => 'json'
	);
	$response = $consumer->sendRequest(constant('REQUEST_URI').'/device/turnOn', $params, 'GET');
	echo $response->getBody();

Within 20 minutes I was turning ceiling lights, floor lamps and all manner of other gadgets on and off from my tablet!

The code is hacky and the OAUTH stuff really ought to be done natively in Android to save a step but I’m happy enough with it, with a single Android device I can search for and download some media to the NAS, queue it up on the RaspBMC to play over whichever TV in the house I want and then adjust the lighting in that room (or any room) to suit the mood and all using open source software.


Published at DZone with permission of Gareth Llewellyn, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)