Tuesday, October 25, 2011

Using Siri For Home Automation

I've created a Twilio, Node.js mash up that allows me to control appliances and the thermostat in my house using the iPhone 4S's Siri voice recognition.

Here's a demo of turning on my bedroom fan.



How does this work? From Siri to the end result the chain goes:
  1. Siri 
  2. Twilio SMS number
  3. Node web application
  4. Indigo Web Server
  5. Insteon thermostat/appliance

Let's go through the setup in reverse order in more detail.


Insteon and Indigo

I purchased the following items last year from Amazon to add some basic home automation to my house.

I have a Mac Mini I use as a server which is connected to the PowerLinc Modem via USB. The Indigo software communicates two-way with the Insteon devices in my home via the PowerLinc. In addition to a native iPhone app, the Indigo software has both a web interface and RESTful Api you can use to control your devices.


Node.js Web Application

The Node.js application is the middle man between Twilio and the Indigo web server. When Twilio POSTs the incoming SMS message to the Node app, it parses the message and determines the appropriate Api call to make on the Indigo web server. I wrote some semi-fuzzy logic so the phrases you use don't have to be exact.

For hosting the Node app I picked Heroku because it's convenient to use and free.


Twilio

Setting up Twilio was super easy. I created a Twilio account, purchased a phone number for $1/month, and entered the Url of my Node app that receives the incoming SMS messages.


Siri

To make communicating with my Twilio phone number easy I added a contact called "Gladys" (could be anything but I'm a Portal fan) and associated the Twilio number with her.

I can now control my appliances using the following commands:
  • Tell Gladys to set thermostat to 73
  • Tell Gladys to turn off the bedroom fan


I originally wanted to turn this into a public Siri to Url web service, but I question the demand for such a thing considering trying to make this "generic" would take a lot of time. So if you're interested in adding Siri control to your own use case and don't have programming skills, I'm available for hire and can whip you up something to suite your exact needs. ;)

UPDATE 10/28/2011:
Big thanks to technabob for the coverage! He brought up a good point though, this could easily be faked. Here's a screen shot of my Heroku logs with debugging output on the left and Node.js code for the "fuzzy logic" on the right. Not indisputable evidence but I assure you it's working exactly like it does in the video. ;)

Sunday, October 16, 2011

Windows 7 Registry Entry to Search All File Contents

If you do a search in Windows 7 you may notice that it didn't find some files that you know contain the search terms you are looking for.
This is due to the What to search setting in Windows Explorer under Folder Options -> Search as pictured below.


If you don't have Always search file names and contents selected Windows will only search the files it has indexed.

You can change the setting using the UI as shown above but you can also set it by changing the following Registry setting (which is useful if you want to programmatically set if for users):

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Search\PrimaryProperties\UnindexedLocations]

"SearchOnly"=dword:00000000

Originally I tried to change the following key based on Scott Forsyth's solution for Windows XP and Windows Server 2003 but it didn't work for me on Windows 7:

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ContentIndex]

"FilterFilesWithUnknownExtensions"=dword:00000001


As a bonus tip, this is how I found where the Windows 7 registry key was.
  1. Open Registry Editor
  2. Right click the registry hive you suspect the setting to be in (usually either HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE) and select Export and save the .reg file (ex: hklm1.reg)
  3. Change the setting via normal means.
  4. Repeat steps 2 and 3 and save the file with a new name (ex: hklm2.reg).
  5. Use a Diff tool such as the one include with Tortoise SVN or Tortoise Git to search for changes.

Wednesday, September 28, 2011

jQuery Mobile Displaying A Dialog

While working on a mobile web app that is using jQuery Mobile I wanted to display a dialog without making an Ajax call to the server to load it which is the "out of the box" way to do it.

Initially I couldn't figure out how to do this but after some reading and thinking it's ridiculously easy.

You have to use a multi-page template which means you have more then one jQuery Mobile "page" container. Example:
<div data-role="page" data-theme="a">
    <div data-role="header" class="header">
        <a href="#menu" data-icon="grid" data-theme="b" data-iconpos="notext" data-transition="pop">&nbsp;</a>
        <h1>My Web App</h1>
        
    </div>

    <div id="map" data-role="content" data-theme="d">
        <p>This is my main content</p>
    </div>
    
    <div data-role="footer">
        <div>
        by <a href="http://cdeutsch.com" rel="external">CDeutsch</a>
        </div>
    </div>
</div>

<!--start menu-->
<div id="menu" data-role="dialog" data-theme="a" data-url="menu">
    <div data-role="header" class="header">
        <h1>Main Menu</h1>
    </div>
    <div data-role="content" data-theme="d">
        <ul data-role="listview" data-theme="c">
            <li><a href="http://blog.cdeutsch.com" rel="external">My Blog</a></li>
            <li><a href="http://twitter.com/cdeutsch" rel="external">Twitter</a></li>
        </ul>
    </div>
</div>

I'm using a button on the left side of the header to trigger showing the dialog. Just set the href to the id of the dialog (in this case menu) and you're all set. No more repeatedly hitting the server for a frequently used resource.

See this jsfiddle for a working example.

Tuesday, September 6, 2011

Entity Framework Code First Error: Could not create constraint

While using Entity Framework Code First you will run into an error similar to the one below if you create objects that have a circular reference.

Introducing FOREIGN KEY constraint 'File_Folder' on table 'Filess' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.


The fix is pretty simple but not very intuitive.

Add the following line to your OnModelCreating override of your DbContext:

modelBuilder.Entity<File>().HasRequired(oo => oo.Folder).WithMany(oo => oo.Files).WillCascadeOnDelete(false);

So it looks something like this:

public class FilesystemDB : DbContext
{
 public DbSet<File> Files { get; set; }
 public DbSet<Folder> Folders { get; set; }
 
 protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
  modelBuilder.Entity<File>().HasRequired(oo => oo.Folder).WithMany(oo => oo.Files).WillCascadeOnDelete(false);
 }

}

For the best information on Entity Framework Code First read Morteza Manavi's blog.

Thursday, August 25, 2011

Remove Duplicates From Rdio Playlists

This has driven me nuts ever since I started using Rdio (sign up using this link to support me). I like to listen to other peoples playlists to find new music and if I hear something I like I add the track to my "favorites" playlist. Unfortunately Rdio lets you add the same song multiple times to the same playlist and there isn't an easy way to find and remove duplicates so I end up with Ice Cube's Check Yo Self in my favorites 5 times.

Here's my solution.
1) Install this bookmarklet by dragging it to your bookmarks or right clicking and selecting "add to bookmarks"
2) Browse to the playlist you want to cleanup in Rdio
3) Run the bookmarklet.

If you're interested in other Rdio hacks be sure to checkout my Rdio remote control PartyQ


Saturday, July 30, 2011

OSX Crashes More Then Windows

There! I said it!

For the record, all my computer hardware, phones, and tablets have been Apple for years; but I primarily do programming in .NET which means I still need to use Windows.

I'm on my 3rd Macbook Pro since Sept of 2007 and over that time OSX has consistently crashed more then Windows XP and Windows 7. Up until April of this year, I was primarily booting directly into Windows using Bootcamp and only using OSX 5% of the time and even with 5% use it had more complete lock ups!

Since April I've started running OSX 100% of the time and run Windows 7 off the Bootcamp partition using Parallels.

Since making the switch to 100% of the time I'd estimate OSX does a Black Screen of Death on average 3-4 times per month. I had one waiting for me this morning after leaving the computer on over night.

People think I'm making this up, so I plan to start tweeting every time it crashes for a historical record.

Granted I have a ton of software loaded on OSX, I'm running Parallels, and I use a Diamond BVU195 USB Display Adapter for a second monitor, BUT other then Parallels these are all things I did on Windows as well so I feel it's a fair comparison.

I've had Windows get slow, or weird, or need a reboot. But I can't remember the last Blue Screen of Death I've had, I can usually kill enough process where I can shut down the OS gracefully. I can't say the same for OSX.

I don't plan on switching away from my current setup and I'll be installing Lion soon. I just want people to STFU about how stable OSX is versus Windows, because it's simply not true.

Crash Log
  • 7/30/2011
  • 8/17/2011 (Milestone: first crash of OSX Lion)
  • 9/8/2011
  • 9/19/2011
  • 9/25/2011
  • 9/30/2011
  • 10/14/2011
  • 11/3/2011
  • 5/25/2012
  • 6/22/2012
  • 8/3/2012 (Milestone: first crash of OSX Mountain Lion)
  • 8/9/2012
  • 8/16/2012
  • 8/17/2012
  • 8/17/2012 (second time in one day, grrr)
  • 8/20/2012
  • 8/22/2012
  • 10/14/2012
  • 10/17/2012

Friday, July 15, 2011

ASP.NET MVC3 App Using plupload to Upload Directly to Amazon S3

UPDATE 8/15/2011:
I can't recommend using this for large files (video files). It's very unreliable. Web size image files and normal email attachment sized files would probably do fine. What I ended up doing to get around it was creating a web app on AppHarbor (which runs on EC2) that I upload the files to and it saves them to S3. Since the AppHarbor app is on a different domain you are still limited to Flash and Silverlight support but you do gain file chunking which brings back some reliability. Alternatively to AppHarbor you could setup your own server on Amazon as well.

I created a working example of using plupload to upload files directly to Amazon S3 and threw it on github, since the .NET examples I found on the web we're incomplete or broken.
https://github.com/crdeutsch/MVC3PluploadToAmazonS3

The files that are being uploaded do not even touch your web server. They are posted directly to Amazon. At the moment plupload only supports the Flash and Silverlight plugins as far as I can tell.

The AmazonS3Helper.cs library originated from Cary Abramoff off of this plupload forum thread.

I've made some changed based on iwasrobbed's excellent Ruby on Rails example.

Usage

Upload the crossdomain.xml found in the root of the site to your Amazon S3 Bucket.

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" secure="false" />
</cross-domain-policy>

Modify the settings in HomeController.cs to use your Amazan credentials and set your S3 bucket.

public ActionResult Index()
{
 string acl = "private";
 string bucket = "YOUR S3 BUCKET NAME";
 string accessKeyId = "YOUR AMAZON ACCESS KEY ID";
 string secret = "YOUR AMAZON SECRET ACCESS KEY";
 string policy = AmazonS3Helper.ConstructPolicy(bucket, DateTime.UtcNow.Add(new TimeSpan(0, 10, 0, 0)), acl, accessKeyId);
 string signature = AmazonS3Helper.CreateSignature(policy, secret);

 var model = new PluploadAmazonS3Model()
 {
  AWSAccessKeyId = accessKeyId,
  Policy = policy,
  Signature = signature,
  Bucket = bucket,
  Acl = acl
 };

 return View(model);
}

On the View side you could just use Razor to dump the Model variables directly into your javascript, but I decided to use hidden form variables instead in case you want to move the javascript to its own file where embedding Razor syntax won't work.

Hope this saves somebody else some time!