I am re-vamping my home automation strategy from a home grown publish/subscribe messaging system to use MQTT instead.  I was using Azure Service Bus to connect remote devices such as my phone with devices in my home such as my lawn irrigation system.  This worked well as a messaging infrastructure for remote devices but I wanted to have a more standard messaging infrastructure that could work in my home network without connectivity to the outside world. 

A few reasons why I switched to MQTT:

  • Light weight
  • Many Clients already exist for many platforms and languages
  • Support for on-premise message broker
  • Support for off-premise message broker
  • Support for bridging brokers (on-premise to off-premise)
  • Fast
  • Used by companies like COSM (was Pachube) and Github
  • Simple topic subscription model that is also powerful
  • I don’t want to write a message broker

For the most part I am moving toward having devices in the home that are relatively dumb and having services running on a home server that add the smarts behind the devices.  This will give me the flexibility to change the behavior of the system a lot quicker without the hassle of tearing apart a device to upgrade the software on it.  This means I needed to have my services available all the time.  Placing these services in the cloud for mission critical things would mean I am left with devices in the home that cannot function while my internet connectivity is down.  This was the biggest reason I moved to an off the self pub/sub infrastructure like MQTT.

Like most messaging protocols, MQTT works on the notion of a topic and a message.  The topic is just a unique way of addressing a message.  I struggled a lot and I probably will continue to struggle on what my topic structure for my home automation should look like.  One thing I wanted to do is try to make the topics readable so that troubleshooting message problems would be easier.  Hear are a few standards I am trying to settle on:

  • When a device or service changes state and wishes to notify interested parties the topic will end with /event 
  • When a device or service wants to know the status of another device or service the topic will end with /getstatus
  • When a device or service receives a topic /getstatus the response topic it generates will end with /status
  • When a device or service needs to set the state of another device or service the topic will end with /set

Here are a few examples of topics and messages for my irrigation system:

DescriptionTopicMessage
Zone 1 turned on irrigation/zone/event z1 On
Request the current schedule from the irrigation service. The service will respond to this request by publishing various status topicsirrigation/schedule/getstatus 
Set the time that the irrigation service should start wateringirrigation/schedule/starttime/set09:00 AM
Status of the schedule start time in response to the getstatus requestirrigation/schedule/starttime/status09:00 AM
Set the days of the week that the irrigation system will waterirrigation/schedule/days/setMON WED FRI
Status of the scheduled days of the week in response to the getstatus requestirrigation/schedule/days/statusMON WED FRI
Set the zones that the irrigation system will run and how longirrigation/schedule/zones/setz1 10 z2 8 z3 10
Status of the scheduled zones in response to the getstatus requestirrigation/schedule/zones/statusz1 10 z2 8 z3 10
Sets the zones to run on the irrigation device and how longirrigation/zones/runz1 10 z2 8 z3 10

MQTT does have a concept of publishing messages with a retain bit. This just tells the broker to hang onto the last message for a topic and when a new subscription arrives the client will receive the last message.  I could have used this concept instead of the /getstatus standard that I have show above.  I might change over to using the retain bit but for now the /getstatus works for me. I am also making my messages a little verbose as they tend to contain multiple values that could have been broken down into more granular topics.

Overall I really like how simple MQTT is and it is very easy to get a device like the Netduino to understand MQTT messages.  I am sure I will make modifications on how I actually define my topics and message body over time as I develop more and more devices and services that do useful stuf in my home.    

I am excited about presenting on this topic for the Charlotte Alt.Net users group on May 8th in Charlotte. Head on over to the event posting and sign up to attend.

Here are the details about the talk:

The most recent release of Microsoft Robotics Developer Studio 4 (RDS4) has introduced two very exciting  concepts that make building robotic applications a reality to all developers: Kinect and Reference Platform Design specification.  The Kinect is the hot device that gives a new perspective on sensing your surroundings.  RDS 4 fully supports the Kinect and opens up all kinds of opportunities for awesome applications.  Do you want skeletal tracking in a robotics application, RDS 4 gives you that.  Do you want to perform obstacle avoidance with Kinect's depth sensor, RDS 4 gives you that. Do you want to simulate a Kinect in a virtual environment  to test out your high level code, RDS 4 gives you that.  The Reference Platform gives vendors a common design specification for building a working robot that includes sensors, motors and low level control. This allows for a developer that has little hardware experience to get up and running fast.  In this session I will introduced you to RDS 4 using the Kinect and an Eddie robot.

Eddie Robot http://www.parallax.com/eddie

Microsoft Robotics Developer Studio http://www.microsoft.com/robotics/

I have been building and releasing software for over 20 years now.  One thing I have learned over the years is that if you have a lot of manual steps in your release process then you will end up making mistakes.  There are many tools available that can help reduce those mistakes.  StudioShell is one of those tools and it has some unique characteristics that make it stand out over the rest of the tools I have used for automating release processes.

I have been maintaining software that manages the FIRST Robotics Competition for the last 5 years.  The Team Foundation Server build process for the software has been modified to package up the bits into an MSI installer.  The installer and a manifest file is deployed to a webserver.  This MSI and manifest make up an auto update process for all the events that are scattered across the US.  The problem I have had over the years is that the process of maintaining the Wix files, manifest, and assembly info meant I had to edit the version number for the next release in multiple places.  As you can imagine this was a recipe for easy mistakes that just do not need to exist.

Well I could solve this problem by modifying the build process to checkout the files that needed to have the new version number.  This would certainly remove the manual process of doing this by hand before the build executes.  However I am not a fan of having the build process modifying source files (Wix, manifest and assembly info).  So I was left with automating the manual process outside the build.  This is where StudioShell shines.

First I created a StudioShell Solution Module only because I wanted to be able to automatically change to the directory that the solution is located once the StudioShell view is opened up inside of Visual Studio.  This will allow me to easily launch other powershell scripts and do some relative paths within these scripts. 

Here is what is in the Solution Module:

function Set-Folder
{
    $file = (get-item(get-item dte:\solution).FullName);
    cd $file.DirectoryName
}

"Loading Solution Module" | out-outputpane;

$m = $MyInvocation.MyCommand.ScriptBlock.Module;
$m.OnRemove = {"Unloading Solution Module" | out-outputpane;}

Set-Folder

As you can see in the script it uses the DTE drive to get the full path to the solution and it simply changes to that directory.  Now any scripts executed in the StudioShell host can use relative paths.

Next I needed a new powershell script that did all the manual operations as follows:

  • Prompt for the version number
  • Change the AssemblyFileVersion in the VersionInfo.cs file to have the new version
  • Change the manifest files to have the new version
  • Change the Wix files to have the new version number

Here is what is in the SetVersion.ps1 file:

function Set-Version
{
    Param ([string]$newVersion)
    $tmp = '"' + $newVersion + '.0"'
    (get-item dte:\solution\projects\fms.util.shell\versioninfo.cs\codemodel\assemblyfileversion) | set-itemproperty -name value -value $tmp
    $file = get-item dte:\solution\projects\fms.util.shell\versioninfo.cs
    $file.Save($file.FileName)

    Set-ManifestVersion $newVersion "Full"
    Set-ManifestVersion $newVersion "Delta"
    Set-Wix $newVersion "Full" "Server"
    Set-Wix $newVersion "Full" "App"
    Set-Wix $newVersion "Delta" "Server"
    Set-Wix $newVersion "Delta" "App"
    Set-Wix $newVersion "" "Light"
}
function Get-Version
{
    return (get-item dte:\solution\projects\fms.util.shell\versioninfo.cs\codemodel\assemblyfileversion).Value
}
function Set-ManifestVersion
{
    Param ([string]$newVersion,[string]$installType)
    $tmp = '"' + $newVersion + '"'
    $fileName = ((get-item dte:\solution\projects\fms.util.shell\$installType\manifest.xml).FileName)
    $xml = [xml](get-content $fileName)
    $appsNode = $xml.Manifest.SelectSingleNode("./Versions/ManifestItem").Clone()
    $serverNode = $xml.Manifest.SelectSingleNode("./Versions/ManifestItem").Clone()
    $nodes = $xml.Manifest.SelectNodes("./Versions/ManifestItem")

    $node = $xml.Manifest.SelectNodes("./Versions/ManifestItem[Version='$newVersion']")
    $node | ForEach-Object  {$xml.Manifest.Versions.RemoveChild($_)}

    $appsNode.Version = "$newVersion"
    $appsNode.FileName = "FMSApps$installType.msi"
    $appsNode.InstallerType = "Apps"
    $xml.Manifest.Versions.AppendChild($appsNode)
    
    $serverNode.Version = "$newVersion"
    $serverNode.FileName = "FMSServer$installType.msi"
    $serverNode.InstallerType = "Server"
    $xml.Manifest.Versions.AppendChild($serverNode)
    $xml.Save($fileName)
}
function Set-Wix
{
    Param ([string]$newVersion,[string]$installType,[string]$targetType)
    $tmp = '"' + $newVersion + '"'
    $location = get-location
    $fileName = $location.Path + "\Source\fms.Installer\$targetType\Setup$installType.wxs"
    $xml = [xml](get-content $fileName)
    $node = $xml.Wix.Product
    $node.Version = "$newVersion"
    $nodes = $xml.Wix.Product.Upgrade.UpgradeVersion
    foreach ($node in $nodes)
    {
      if ($node.Property -eq "NEWPRODUCTFOUND")
      {
        $node.Minimum = "$newVersion"
      }
      if ($node.Property -eq "UPGRADEFOUND")
      {
        $node.Maximum = "$newVersion"
      }
    }
    $xml.Save($fileName)
}

$current = Get-Version
Write-Host "The current version is:" $current
$newVersion = read-host "What is the new version you want"
Set-Version $newVersion

As you can see the script is not all that complex.  The DTE drive makes finding resources in the solution and accessing properties of the resource such as file name very easy.  Since the solution is bound to source control, modifying the VersionInfo.cs file automatically checks it out of source control.  I was even able to use the codemodel to easily find the AssemblyFileVersion and set its value to the next version number.

To release the next version of my software I simply launch the StudioShell view and type .\SetVersion in the shell and the script will read the current version from the VersionInfo.cs file and prompt me for the next version number.  After I enter the new version number and hit return the necessary files will be updated and saved.  All I have to do is check in the changes and kick off the build.

In conclusion I was able to use the powerful features of StudioShell to take a very manual multi step process and reduce it down to only a couple steps.