<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Coding4Fun : home automation</title><link>http://blogs.msdn.com/coding4fun/archive/tags/home+automation/default.aspx</link><description>Tags: home automation</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Shutdown/Restart/Logoff your PC using TweetMyPC</title><link>http://blogs.msdn.com/coding4fun/archive/2009/06/23/9709252.aspx</link><pubDate>Tue, 23 Jun 2009 22:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9709252</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/9709252.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=9709252</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=9709252</wfw:comment><description>&lt;p&gt;In this article I will show you how you can use Twitter API to Shutdown/Restart/Logoff your PC remotely using VB.net.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;b&gt;Compiled version: &lt;/b&gt;&lt;a href="http://tweetmypc.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=26541#DownloadId=66390"&gt;CodePlex.com&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;b&gt;Source Code:&lt;/b&gt; &lt;a href="http://tweetmypc.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=26542#DownloadId=66391"&gt;Codeplex.com&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;b&gt;Difficulty:&lt;/b&gt; Beginner&lt;/li&gt;    &lt;li&gt;&lt;b&gt;Time Required:&lt;/b&gt; 2 hours&lt;/li&gt;    &lt;li&gt;&lt;b&gt;Cost:&lt;/b&gt; Free&lt;/li&gt;    &lt;li&gt;&lt;b&gt;Software Needed:&lt;/b&gt; &lt;a href="http://www.microsoft.com/express/download/"&gt;Visual Basic or Visual C# Express&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;b&gt;Libraries: &lt;/b&gt;&lt;a href="http://devblog.yedda.com/index.php/2007/05/16/twitter-c-library/"&gt;Yedda Twitter Library&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Introduction&lt;/h3&gt;  &lt;p&gt;I have a very slow internet connection at home and most of the time Downloads takes hours to complete. I decided to write an application which will help me Shutdown my PC from a remote location. I wanted to use it to shutdown when I go out when some downloading is going on in my laptop. Instead of using a server and client architecture I decided to use Twitter API and use “My Timeline” to supply commands. One other reason to use Twitter is that I will be able to tweet from my mobile as well. I don’t need to look for a computer with an internet connection when I am on the move.&lt;/p&gt;  &lt;h4&gt;Why Yedda Twitter framework?&lt;/h4&gt;  &lt;p&gt;The &lt;a href="http://apiwiki.twitter.com/Twitter-API-Documentation"&gt;Twitter REST API&lt;/a&gt; methods allow developers to access core Twitter data. This includes update timelines, status data, and user information. It’s very easy to connect to Twitter and get user time line using .net. But I dint wanted to reinvent wheel and decided to use an existing Twitter library. Yedda Twitter framework is the best open source Twitter library available in the internet. You can learn more and download the library from &lt;a href="http://devblog.yedda.com/index.php/2007/05/16/twitter-c-library/"&gt;yedda’s home page&lt;/a&gt;.&lt;/p&gt;  &lt;h4&gt;Designing the Interface&lt;/h4&gt;  &lt;p&gt;I wanted the interface to be as simple as possible. Below is the screenshot of TweetMyPC’s interface which does not have more than 2 Text Boxes, 1 Check Box, Label and a Button.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/ShutdownRestartLogoffyourPCusingTweetMyP_D2B1/clip_image001_2.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="clip_image001" border="0" alt="clip_image001" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/ShutdownRestartLogoffyourPCusingTweetMyP_D2B1/clip_image001_thumb.jpg" width="288" height="250" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The form also has a Notify Icon, Context Menu Strip and a Timer. Following are the names of all the controls in the form.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;From : &lt;b&gt;frmTweetMyPc&lt;/b&gt;&lt;/li&gt;    &lt;li&gt;Text Boxes : &lt;b&gt;txtUserName&lt;/b&gt;, &lt;b&gt;txtPassword&lt;/b&gt;&lt;/li&gt;    &lt;li&gt;Button : &lt;b&gt;btnSave&lt;/b&gt;&lt;/li&gt;    &lt;li&gt;Check Box : &lt;b&gt;chkStartAutomatic&lt;/b&gt;&lt;/li&gt;    &lt;li&gt;Timer : &lt;b&gt;tmrTweet&lt;/b&gt; (Interval : 10000)&lt;/li&gt;    &lt;li&gt;Label : &lt;b&gt;lblSatus&lt;/b&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;There are few &lt;a href="http://msdn.microsoft.com/en-us/library/saa62613(VS.80).aspx"&gt;My.settings&lt;/a&gt; properties to store user information. These properties are shown below.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/ShutdownRestartLogoffyourPCusingTweetMyP_D2B1/clip_image002_2.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="clip_image002" border="0" alt="clip_image002" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/ShutdownRestartLogoffyourPCusingTweetMyP_D2B1/clip_image002_thumb.jpg" width="388" height="139" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;b&gt;The Code&lt;/b&gt;&lt;b&gt;     &lt;br /&gt;&lt;/b&gt;Add the following code which minimizes the Form on Load and Enable Timer to check for Tweets every 1 minute. &lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;Me&lt;/span&gt;.WindowState = FormWindowState.Minimized
&lt;span class="kwrd"&gt;Me&lt;/span&gt;.ShowInTaskbar = &lt;span class="kwrd"&gt;False&lt;/span&gt;
tmrTweet.Enabled = True&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The following code in Button’s Click event will validate Twitter username, Password and save it to My.Settings.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;If&lt;/span&gt; txtUserName.Text.Trim = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;
    lblSatus.Text = &lt;span class="str"&gt;&amp;quot;Please enter Twitter Username&amp;quot;&lt;/span&gt;
    txtUserName.Focus()
    &lt;span class="kwrd"&gt;Exit&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;
&lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;
&lt;span class="kwrd"&gt;If&lt;/span&gt; txtPassword.Text.Trim = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;
    lblSatus.Text = &lt;span class="str"&gt;&amp;quot;Please enter Twitter Password&amp;quot;&lt;/span&gt;
    txtPassword.Focus()
    &lt;span class="kwrd"&gt;Exit&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;
&lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

lblSatus.Text = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;


&lt;span class="rem"&gt;'Check for valid Username and Password and then Save Settings&lt;/span&gt;
&lt;span class="kwrd"&gt;Dim&lt;/span&gt; objTwitter &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; Yedda.Twitter
&lt;span class="kwrd"&gt;Dim&lt;/span&gt; Updates &lt;span class="kwrd"&gt;As&lt;/span&gt; XmlDocument

&lt;span class="kwrd"&gt;Try&lt;/span&gt; &lt;span class="rem"&gt;'Try Logging in&lt;/span&gt;
    Updates = objTwitter.GetUserTimelineAsXML(txtUserName.Text.Trim, txtPassword.Text.Trim)
    My.Settings.UserName = txtUserName.Text.Trim
    My.Settings.Password = txtPassword.Text.Trim
    &lt;span class="kwrd"&gt;Me&lt;/span&gt;.WindowState = FormWindowState.Minimized
    &lt;span class="kwrd"&gt;Me&lt;/span&gt;.ShowInTaskbar = &lt;span class="kwrd"&gt;False&lt;/span&gt;
    tmrTweet.Enabled = &lt;span class="kwrd"&gt;True&lt;/span&gt;
&lt;span class="kwrd"&gt;Catch&lt;/span&gt; ex &lt;span class="kwrd"&gt;As&lt;/span&gt; Exception
    MsgBox(&lt;span class="str"&gt;&amp;quot;Failed to Login to Twitter with the values supplied. Please check your login details.&amp;quot;&lt;/span&gt;)
    txtUserName.Focus()
    &lt;span class="kwrd"&gt;Exit&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;
&lt;span class="kwrd"&gt;End&lt;/span&gt; Try&lt;/pre&gt;

&lt;p&gt;Yedda library is used to login to Twitter to check for valid username and password. The Label &lt;b&gt;lblSatus&lt;/b&gt; is used to display any error messages.&lt;/p&gt;

&lt;p&gt;Add the following code to the Checkbox’s &lt;strong&gt;CheckChanged&lt;/strong&gt; event which will add the required registry keys to start this app on Window’s startup&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;If&lt;/span&gt; chkStartAutomatic.Checked = &lt;span class="kwrd"&gt;True&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; My.Settings.AutomaticStart = &lt;span class="kwrd"&gt;True&lt;/span&gt;
      &lt;span class="kwrd"&gt;Dim&lt;/span&gt; regKey &lt;span class="kwrd"&gt;As&lt;/span&gt; RegistryKey
      regKey = Registry.CurrentUser.OpenSubKey(&lt;span class="str"&gt;&amp;quot;Software\Microsoft\Windows\CurrentVersion\Run&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;True&lt;/span&gt;)
      regKey.SetValue(Application.ProductName, Application.ExecutablePath)
      regKey.Close()
&lt;span class="kwrd"&gt;Else&lt;/span&gt;
      My.Settings.AutomaticStart = &lt;span class="kwrd"&gt;False&lt;/span&gt;
      &lt;span class="kwrd"&gt;Dim&lt;/span&gt; regKey &lt;span class="kwrd"&gt;As&lt;/span&gt; RegistryKey
      regKey = Registry.CurrentUser.OpenSubKey(&lt;span class="str"&gt;&amp;quot;Software\Microsoft\Windows\CurrentVersion\Run&amp;quot;&lt;/span&gt;, &lt;span class="kwrd"&gt;True&lt;/span&gt;)
      regKey.DeleteValue(Application.ProductName)
      regKey.Close()
&lt;span class="kwrd"&gt;End&lt;/span&gt; If&lt;/pre&gt;

&lt;p&gt;The following code in Timer’s Tick event will do the job of checking Twitter Timeline every one minute and Shutdown/Restart/Log off the system based on the Tweet.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;If&lt;/span&gt; My.Settings.UserName.Trim = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;
    &lt;span class="kwrd"&gt;Exit&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;
&lt;span class="kwrd"&gt;Else&lt;/span&gt;
    &lt;span class="rem"&gt;'Check for new Tweet &lt;/span&gt;
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; objTwitter &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; Yedda.Twitter
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; Updates &lt;span class="kwrd"&gt;As&lt;/span&gt; XmlDocument
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; node &lt;span class="kwrd"&gt;As&lt;/span&gt; XmlNode
    &lt;span class="kwrd"&gt;Try&lt;/span&gt; &lt;span class="rem"&gt;'Try Logging in&lt;/span&gt;
        Updates = objTwitter.GetUserTimelineAsXML(My.Settings.UserName.Trim, My.Settings.Password.Trim)
        &lt;span class="kwrd"&gt;Catch&lt;/span&gt; ex &lt;span class="kwrd"&gt;As&lt;/span&gt; Exception
        MsgBox(&lt;span class="str"&gt;&amp;quot;Error : Failed to Login to Twitter with the values supplied. Please check your login details.&amp;quot;&lt;/span&gt;)
        &lt;span class="kwrd"&gt;Exit&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Try&lt;/span&gt;
    &lt;span class="kwrd"&gt;Try&lt;/span&gt;
        node = Updates.SelectSingleNode(&lt;span class="str"&gt;&amp;quot;/statuses/status/id&amp;quot;&lt;/span&gt;)
        &lt;span class="kwrd"&gt;If&lt;/span&gt; node.InnerText.Trim &amp;lt;&amp;gt; My.Settings.LastID.Trim &lt;span class="kwrd"&gt;Then&lt;/span&gt; 
            &lt;span class="rem"&gt;'Compare the Tweet ID to check for new tweets&lt;/span&gt;
            My.Settings.LastID = node.InnerText.Trim
            node = Updates.SelectSingleNode(&lt;span class="str"&gt;&amp;quot;/statuses/status/text&amp;quot;&lt;/span&gt;)
            ProcessTweet(node.InnerText.Trim)
          &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;
    &lt;span class="kwrd"&gt;Catch&lt;/span&gt; ex &lt;span class="kwrd"&gt;As&lt;/span&gt; Exception
        &lt;span class="kwrd"&gt;Exit&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Try&lt;/span&gt;
&lt;span class="kwrd"&gt;End&lt;/span&gt; If&lt;/pre&gt;

&lt;p&gt;If the Tweet is new then we process the tweet.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; ProcessTweet(&lt;span class="kwrd"&gt;ByVal&lt;/span&gt; Tweet &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt;)
    &lt;span class="kwrd"&gt;If&lt;/span&gt; Tweet = &lt;span class="str"&gt;&amp;quot;Shutdown&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;
        System.Diagnostics.Process.Start(&lt;span class="str"&gt;&amp;quot;shutdown&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;-s -f -t 100&amp;quot;&lt;/span&gt;) &lt;span class="rem"&gt;'Shutdown&lt;/span&gt;
    &lt;span class="kwrd"&gt;ElseIf&lt;/span&gt; Tweet = &lt;span class="str"&gt;&amp;quot;Logoff&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;
        System.Diagnostics.Process.Start(&lt;span class="str"&gt;&amp;quot;shutdown&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;-l -f -t 100&amp;quot;&lt;/span&gt;) &lt;span class="rem"&gt;'Logoff&lt;/span&gt;
    &lt;span class="kwrd"&gt;ElseIf&lt;/span&gt; Tweet = &lt;span class="str"&gt;&amp;quot;Restart&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;
        System.Diagnostics.Process.Start(&lt;span class="str"&gt;&amp;quot;shutdown&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;-r -f -t 100&amp;quot;&lt;/span&gt;) &lt;span class="rem"&gt;' Restart&lt;/span&gt;
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;
&lt;span class="kwrd"&gt;End&lt;/span&gt; Sub&lt;/pre&gt;

&lt;p&gt;The Context Menu strip has two menu items. They are Edit Setting and Exit.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/ShutdownRestartLogoffyourPCusingTweetMyP_D2B1/clip_image003_2.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="clip_image003" border="0" alt="clip_image003" src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/ShutdownRestartLogoffyourPCusingTweetMyP_D2B1/clip_image003_thumb.jpg" width="292" height="253" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add the following code the “Edit Settings” Client event and Notify Icon’s Mouse Double Click Event. &lt;/p&gt;

&lt;pre class="csharpcode"&gt;tmrTweet.Enabled = &lt;span class="kwrd"&gt;False&lt;/span&gt;
txtUserName.Text = My.Settings.UserName.Trim
txtPassword.Text = My.Settings.Password.Trim
&lt;span class="kwrd"&gt;If&lt;/span&gt; My.Settings.AutomaticStart = &lt;span class="kwrd"&gt;True&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt; chkStartAutomatic.Checked = &lt;span class="kwrd"&gt;True&lt;/span&gt;
&lt;span class="kwrd"&gt;Me&lt;/span&gt;.WindowState = FormWindowState.Normal
&lt;span class="kwrd"&gt;Me&lt;/span&gt;.ShowInTaskbar = True&lt;/pre&gt;

&lt;p&gt;TweetMyPC runs silently on startup. To Edit Settings double click/Right Click the notify icon.&lt;/p&gt;

&lt;h4&gt;Working&lt;/h4&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:60558cb3-f672-4422-85cf-fea80c9effce" class="wlWriterEditableSmartContent"&gt;&lt;div id="28e191ed-c541-4d5a-85ef-992feaf927fd" style="margin: 0px; padding: 0px; display: inline;"&gt;&lt;div&gt;&lt;a href="http://www.youtube.com/watch?v=yPxd2IwWjoU" target="_new"&gt;&lt;img src="http://blogs.msdn.com/blogfiles/coding4fun/WindowsLiveWriter/ShutdownRestartLogoffyourPCusingTweetMyP_D2B1/video770b8dbba191.jpg" style="border-style: none" galleryimg="no" onload="var downlevelDiv = document.getElementById('28e191ed-c541-4d5a-85ef-992feaf927fd'); downlevelDiv.innerHTML = &amp;quot;&amp;lt;div&amp;gt;&amp;lt;object width=\&amp;quot;425\&amp;quot; height=\&amp;quot;355\&amp;quot;&amp;gt;&amp;lt;param name=\&amp;quot;movie\&amp;quot; value=\&amp;quot;http://www.youtube.com/v/yPxd2IwWjoU&amp;amp;hl=en\&amp;quot;&amp;gt;&amp;lt;\/param&amp;gt;&amp;lt;embed src=\&amp;quot;http://www.youtube.com/v/yPxd2IwWjoU&amp;amp;hl=en\&amp;quot; type=\&amp;quot;application/x-shockwave-flash\&amp;quot; width=\&amp;quot;425\&amp;quot; height=\&amp;quot;355\&amp;quot;&amp;gt;&amp;lt;\/embed&amp;gt;&amp;lt;\/object&amp;gt;&amp;lt;\/div&amp;gt;&amp;quot;;" alt=""&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Even though TweetMyPC is a simple app it has lot of interesting potential. Think about switching off your TV or washing machine using Twitter. It is possible with a little extra hardware and a simple .net program. TweetMyPC is free and open source. Feel free to download the sour code and add more functionality.&lt;/p&gt;

&lt;h3&gt;About The Author&lt;/h3&gt;

&lt;p&gt;Shoban Kumar is a Senior Software Engineer working for Allianz Cornhill India. Programming is his passion. He also writes about .net in &lt;a href="http://www.dotnetcurry.com/"&gt;http://www.dotnetcurry.com/&lt;/a&gt; and an active participator in &lt;a href="http://stackoverflow.com/users/12178/shoban"&gt;stackoverflow&lt;/a&gt; and speaker in &lt;a href="http://k-mug.org/"&gt;Microsoft user group&lt;/a&gt; sessions. You also can follow him in &lt;a href="http://twitter.com/shobankr"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9709252" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/utility/default.aspx">utility</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/home+automation/default.aspx">home automation</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/windows/default.aspx">windows</category></item><item><title>Controlling Your Festive Lights with the .NET Micro Framework</title><link>http://blogs.msdn.com/coding4fun/archive/2008/11/27/9149635.aspx</link><pubDate>Fri, 28 Nov 2008 07:58:46 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9149635</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/9149635.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=9149635</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=9149635</wfw:comment><description>&lt;table class="" cellspacing="0" cellpadding="2" width="470" border="0"&gt;&lt;tbody&gt;     &lt;tr&gt;&lt;/tr&gt;      &lt;tr&gt;       &lt;td class="" valign="top" width="105"&gt;&lt;strong&gt;Author:&lt;/strong&gt;&lt;/td&gt;        &lt;td class="" valign="top" width="363"&gt;Rob Miles: &lt;a href="http://www.robmiles.com"&gt;www.robmiles.com&lt;/a&gt; &lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td class="" valign="top" width="105"&gt;&lt;strong&gt;Download:&lt;/strong&gt;&lt;/td&gt;        &lt;td class="" valign="top" width="363"&gt;&lt;a title="http://coding4fun.net/source/festivelights1.0.zip" href="http://coding4fun.net/source/festivelights1.0.zip"&gt;http://coding4fun.net/source/festivelights1.0.zip&lt;/a&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td class="" valign="top" width="105"&gt;&lt;strong&gt;Software:&lt;/strong&gt;&lt;/td&gt;        &lt;td class="" valign="top" width="363"&gt;Visual Studio 2008 Express Edition or better,          &lt;br /&gt;&lt;a href="http://www.microsoft.com/netmf/about/gettingstarted.mspx"&gt;.NET Micro Framework 3.0&lt;/a&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td class="" valign="top" width="105"&gt;&lt;strong&gt;Hardware:&lt;/strong&gt;&lt;/td&gt;        &lt;td class="" valign="top" width="363"&gt;&lt;a href="http://www.digi.com/products/embeddedsolutions/digiconnectme.jsp"&gt;Digi Connect-ME&lt;/a&gt;           &lt;br /&gt;&lt;a href="http://www.ghielectronics.com/embeddedmaster.php"&gt;GHI Electronics Embedded Master&lt;/a&gt;           &lt;br /&gt;&lt;a href="http://devicesolutions.net/Products/Tahoe.aspx"&gt;Devices Solutions Tahoe II &lt;/a&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td class="" valign="top" width="105"&gt;&lt;strong&gt;Time Required:&lt;/strong&gt;&lt;/td&gt;        &lt;td class="" valign="top" width="363"&gt;3 hours&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td class="" valign="top" width="105"&gt;&lt;strong&gt;Cost:&lt;/strong&gt;&lt;/td&gt;        &lt;td class="" valign="top" width="363"&gt;30 dollars for lights plus the .NET Micro Framework device&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;The Micro Framework is one of the newest kids on the .NET block, but it does something really rather wonderful. It brings embedded development within the reach of any C# programmer. If you know C# and love Visual Studio, you can now get started building hardware and controlling it with your software. Moreover, it lets developers achieve one of their most cherished dreams, to control their festive lights using programs that they have written. This project shows you how to do just that and adds an extra magical feature, in that you can make all your festive lights flash red whenever I, Rob Miles, make a new post on that most famous of blogs, &lt;a href="http://www.robmiles.com"&gt;www.robmiles.com&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;Actually, you can modify the code so that you can make your lights do most anything in response to an event that happens on the web. You could signal home that you are running late, send the weather forecast to your Christmas tree or explore any number of communication options. You might decide that this is so useful that you leave your decorations up all year round.&lt;/p&gt;  &lt;p&gt;If you just want to play with the .NET Micro Framework and get a feel for how easy it is to create software for tiny devices you don't actually need to use any extra hardware at all. The project comes with a complete emulation of the lights display so that you can run the whole thing on your computer and learn how hardware and software can be made to work together without burning your fingers with a soldering iron.&lt;/p&gt;  &lt;p&gt;However building the hardware will give you an understanding of how some simple electronic components can be controlled from C# and even how serial and parallel data transfer works. It is also great fun.&lt;/p&gt;  &lt;p&gt;To get started you will need some hardware and some software. Let's take each in turn.&lt;/p&gt;  &lt;h1&gt;Hardware&lt;/h1&gt;  &lt;h2&gt;Processor Hardware&lt;/h2&gt;  &lt;p&gt;The .NET Micro Framework lets you run C# programs on tiny embedded devices. There are a number of these available today, and they are getting progressively cheaper. You can base this project on any.NET Micro Framework device that has a network port and three or more output ports. The ones I'd recommend are:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Digi Connect-ME: &lt;a href="http://www.digi.com/products/embeddedsolutions/digiconnectme.jsp"&gt;http://www.digi.com/products/embeddedsolutions/digiconnectme.jsp&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;GHI Electronics Embedded Master: &lt;a href="http://www.ghielectronics.com/embeddedmaster.php"&gt;http://www.ghielectronics.com/embeddedmaster.php&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Devices Solutions Tahoe II: &lt;a href="http://devicesolutions.net/Products/Tahoe.aspx"&gt;http://devicesolutions.net/Products/Tahoe.aspx&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I built the project for Digi Connect board but the code can be customised for any of the above platforms. The beauty of the .NET Micro Framework is that you hardly need to change your program even if the underlying hardware is completely replaced. The only thing you will have to do is adjust the code to target different output pins. I'll flag this part of the program up when we get to it.&lt;/p&gt;  &lt;p&gt;The project as supplied runs on a special emulator that runs on the PC and behaves like a .NET Micro Framework device with lights connected, so you can get started exploring the code right away.&lt;/p&gt;  &lt;h2&gt;Lights&lt;/h2&gt;  &lt;p&gt;I'm keeping things deliberately low voltage for this project. This means that kids of all ages can have a go at building the hardware without messing around with mains. The lights that I used were supplied as lines of twenty leds wired up as four strands of five leds each. All the leds in each strand were the same colour. The lights were fitted with a little battery box which held three AA batteries and a tiny controller. To get my display I simply removed the battery box and connected the strands to my hardware.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/8258df29ac59_13B9C/image.png"&gt;&lt;img title="image" style="display: inline" height="226" alt="image" src="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_thumb.png" width="324" border="0" /&gt;&lt;/a&gt;&amp;#160; &lt;br /&gt;&lt;strong&gt;Figure 1: My Battery Powered Lights&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;You can do the same with any low power lighting kit that you wish to use. The drivers that I'm using can handle around 500 milliamps of continuous current and so you can connect a fair number of lights to each strand. &lt;/p&gt;  &lt;h2&gt;Buying the Lights&lt;/h2&gt;  &lt;p&gt;The lights I used can be bought in the UK from Lights4Fun: www.lights4fun.co.uk and are called &amp;quot;C-LED-4.5-M 20 Multi Coloured Battery Operated LED Fairy Lights&amp;quot;. They are supplied with a battery box and controller that you can remove to connect to the Darlington drivers. I used an old 5 volt mobile phone charger to power the lights. If you search eBay for &amp;quot;led christmas lights battery&amp;quot; you should find plenty of suppliers.&lt;/p&gt;  &lt;h2&gt;Driver Hardware&lt;/h2&gt;  &lt;p&gt;We can't connect a .NET Micro Framework device directly to our lights. There are two reasons for this:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;The Micro Framework device will not be able to switch the amount of current that we need to drive the lights themselves.&lt;/li&gt;    &lt;li&gt;The Micro Framework device will not have enough outputs to control all the lights that we want to use.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;This means that we need to make some hardware that goes between the processor and our lights. I actually don't see this as a problem. Making hardware is great fun, seeing something that you've built spring into life is very nice. The hardware we are going to use will provide a means by which we can control many hundreds of lights from a single Micro Framework board if we wish. It also has the ability to switch reasonable amounts of current, so you can use quite large numbers of lights if you wish. We are going to use two semiconductor components, a CD4094 Shift Register/Latch and a ULN2803 Octal Darlington Driver. A pair of these chips will allow us to control 8 outputs. If you want to control more outputs you simply get more chips and chain them together. For my version of the project I just used one of each chip, you can use as many as you like.The shift registers and Darlington amplifiers can be obtained in the UK from Maplin: &lt;a href="http://www.maplin.co.uk"&gt;www.maplin.co.uk&lt;/a&gt;. The chip numbers and part numbers as are as follows: QW54J 4094 Shift Register, QY79L ULN2803A Darlington Driver. In the US you can obtain the components and breadboard from Digi-Key: &lt;a href="http://www.digikey.com"&gt;www.digikey.com&lt;/a&gt;. &lt;/p&gt;  &lt;h2&gt;Serial and Parallel Data&lt;/h2&gt;  &lt;p&gt;You might be wondering how we can use just three output lines to control lots of lights. We are going to do this by using the three output lines to provide a &lt;i&gt;serial&lt;/i&gt; data stream which is converted by our hardware into &lt;i&gt;parallel&lt;/i&gt; data that can be used to control our lights. This is a fundamental principle of digital electronics and is how, amongst many other things, computer networks transfer data.&lt;/p&gt;  &lt;p&gt;We are going to use three signals which are called &lt;b&gt;clock&lt;/b&gt;, &lt;b&gt;data&lt;/b&gt; and &lt;b&gt;latch&lt;/b&gt;. Each of these can be set high (a voltage is present) or low (no voltage is present) by the .NET Micro Framework device under the control of our software. The signals are connected to the clock, data and latch inputs of our CD4094 shift register so that the program can talk to it.&lt;/p&gt;  &lt;p&gt;The clock line triggers the shift register to do two things:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Shift all the bits along to make room.&lt;/li&gt;    &lt;li&gt;Sample the value of the data input and store this value in the space that was created.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;To get a feel for how this works, take a look at Figure 2 below. It shows a shift register with a pattern of bits in it. The pattern is &lt;b&gt;01100001&lt;/b&gt;. Note that although this represents a number; it can also be regarded as a pattern of 0s and 1s in the shift register itself. The value 0 means 0 volts and the value 1 means some volts. These are the signals that will be used to control our lights. I'm going to call them 0 and 1 from now on. The Shift Register has Clock, Data and Latch signals connected and they are all set to 1. We can ignore the latch part of the chip for now.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_3.png"&gt;&lt;img title="image" style="display: inline" height="251" alt="image" src="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_thumb_3.png" width="500" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Figure 2: A shift register and latch with some data in it&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;When the clock signal changes from 1 to 0 this causes the shift register to perform the two steps described above. First the data is shifted along to the right. Note that this means that there is an &amp;quot;empty&amp;quot; location at the start of the register, and that the right most bit in the register &amp;quot;falls off&amp;quot; the register and disappears. Figure 3 shows how this works.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_4.png"&gt;&lt;img title="image" style="display: inline" height="236" alt="image" src="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_thumb_4.png" width="500" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Figure 3: Shifting along the values in the shift register&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Once the shift has finished the shift register can copy the data signal into the empty bit at the left as shown in Figure 4 below.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_5.png"&gt;&lt;img title="image" style="display: inline" height="251" alt="image" src="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_thumb_5.png" width="500" border="0" /&gt;&lt;/a&gt; &lt;strong&gt;     &lt;br /&gt;Figure 4: Storing the new data bit&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;By repeating this process 8 times a program can load a new pattern of 8 bits into the shift register. Then it is time to latch the new value to control the lights. This is the point at which the lights will appear to change. When the latch value is changed from 0 to 1 this causes the chip to copy the value in the Shift Register into the latch, as shown in Figure 5 below.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_6.png"&gt;&lt;img title="image" style="display: inline" height="251" alt="image" src="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_thumb_6.png" width="500" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Figure 5: Copying the shift register pattern into the latch.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The latch is required so that the lights will not flicker as the new patterns are shifted into position. Each of the bits in the latch is connected to an output pin on the CD4094 which is used to switch a particular light colour on or off.&lt;/p&gt;  &lt;p&gt;We need to create some C# that will provide the appropriate sequence of signals. It turns out that using the .NET Micro Framework to achieve this is actually very easy. The &lt;b&gt;displayByte&lt;/b&gt; method below sends an 8 bit value into a shift register and then latches it into the output. If you read through the code you can see how the clock, data and latch values are all set to true (high) or false (low) to first clock the data out and then trigger the latch to display the pattern on the lights. The input is an 8 bit byte value and the program uses a mask to pick out the value of each bit in turn and set the data output accordingly.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; displayByte(&lt;span class="kwrd"&gt;byte&lt;/span&gt; &lt;span class="kwrd"&gt;value&lt;/span&gt;)
{
    latchPort.Write(&lt;span class="kwrd"&gt;false&lt;/span&gt;);
    clockPort.Write(&lt;span class="kwrd"&gt;false&lt;/span&gt;);

    &lt;span class="kwrd"&gt;byte&lt;/span&gt; mask = 1;

    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 8; i++)
    {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; ((&lt;span class="kwrd"&gt;value&lt;/span&gt; &amp;amp; mask) &amp;gt; 0)
        {
            dataPort.Write(&lt;span class="kwrd"&gt;true&lt;/span&gt;);
        }
        &lt;span class="kwrd"&gt;else&lt;/span&gt;
        {
            dataPort.Write(&lt;span class="kwrd"&gt;false&lt;/span&gt;);
        }
        clockPort.Write(&lt;span class="kwrd"&gt;true&lt;/span&gt;);
        clockPort.Write(&lt;span class="kwrd"&gt;false&lt;/span&gt;);
        mask &amp;lt;&amp;lt;= 1;
    }
    latchPort.Write(&lt;span class="kwrd"&gt;true&lt;/span&gt;);
    latchPort.Write(&lt;span class="kwrd"&gt;false&lt;/span&gt;);
}&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The &lt;b&gt;dataPort&lt;/b&gt;, &lt;b&gt;clockPort&lt;/b&gt; and &lt;b&gt;latchPort&lt;/b&gt; variables are instances of the .NET Micro Framework class &lt;b&gt;OutputPort&lt;/b&gt;, which provides a method called &lt;b&gt;Write&lt;/b&gt; which can be used to control the state of the output signal. We will consider how these are created a little later in the article.&lt;/p&gt;

&lt;p&gt;The sample code for this project comes with a software emulator of the CD4094 which shows how it works. Figure 6 below shows that a new pattern is in the process of being shifted into the shift register, while the lights retain the previous one in the latch. The Clock and Data signals are high and the next statement will drop the Clock signal to add the next bit into the new pattern.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_7.png"&gt;&lt;img title="image" style="display: inline" height="303" alt="image" src="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_thumb_7.png" width="264" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 6: The light emulator&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This figure also shows that I have two bits in the pattern controlling a strand of each colour. You can single step through the displayByte method above and watch it perform this output.&lt;/p&gt;

&lt;p&gt;You can use this technique every time you want to control a large number of outputs using a small number of output pins. The CD4094 has &amp;quot;daisy chain&amp;quot; inputs and outputs so that the devices can be connected in sequence. If I used two devices I could control 16 bits, with three I could control 24 and so on. This would require only minimal changes to the software.&lt;/p&gt;

&lt;h2&gt;Output Driver&lt;/h2&gt;

&lt;p&gt;The CD4094 device will produce a signal output, but it is not really powerful enough to drive things like lights. To do this we need an amplifier and the ULN2803 Octal Darlington Driver is perfect for this. It is packaged as a single chip which contains 8 pairs of transistors. Each transistor pair is wired in a &amp;quot;Darlington&amp;quot; configuration and can be used as a switch which is controlled by on output from the CD4094. When the transistors are turned on they allow current to pass through them and this will cause the lamps to light. The lights that I bought used a &amp;quot;pull down&amp;quot; arrangement to make them light up. All of the light emitting diode (LED) lamps had one end wired to a common line that was connected to the positive supply. To make the a chain of LEDs light the other end that controls that chain needed to be pulled down to the ground level. This is a common arrangement with lights like these. The ULN2803 driver has the transistors wired in an arrangement that allows it to pull signals low in this way. Figure 7 shows how this arrangement works. The resistor shown is actually wired into each LED in the set of lights that I used.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_8.png"&gt;&lt;img title="image" style="display: inline" height="201" alt="image" src="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_thumb_8.png" width="226" border="0" /&gt;&lt;/a&gt; 

  &lt;br /&gt;&lt;strong&gt;Figure 7: Lighting the LEDs&lt;/strong&gt;&lt;/p&gt;

&lt;h5&gt;Complete Circuit&lt;/h5&gt;

&lt;p&gt;The complete circuit shown in Figure 8 simply links each output of the CD4094 shift register to an input on the ULN2803 Darlington Driver. Note that there is no reason to link any particular bit with any other, the diagram shown is one which will translate most easily to a prototype &amp;quot;breadboard&amp;quot;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_9.png"&gt;&lt;img title="image" style="display: inline" height="260" alt="image" src="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_thumb_9.png" width="500" border="0" /&gt;&lt;/a&gt; 

  &lt;br /&gt;&lt;strong&gt;Figure 8: The Complete Circuit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The diagram just shows four lights connected to OUT1 from pin 18 of the ULN2803, the other 7 channels are connected in exactly the same way. Some of the pins can be left unconnected. Pins 9 and 10 of the CD4094 are only required if you are connecting multiple shift registers together and the common connection on pin 10 of the ULN2803 is not required. The Latch, Data and Clock signals on the CD4094 are connected to the output signals from the Micro Framework device. &lt;/p&gt;

&lt;p&gt;Figure 9 shows the completed circuit built up on a prototype breadboard. The chip on the left is the CD4094 and the one on the right is the ULN2803.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_10.png"&gt;&lt;img title="image" style="display: inline" height="331" alt="image" src="http://www.coding4fun.net/images/8258df29ac59_13B9C/image_thumb_10.png" width="484" border="0" /&gt;&lt;/a&gt; &lt;strong&gt;
    &lt;br /&gt;Figure 9: The Completed Circuit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The red wires carry the positive voltage from the power supply, which is connected to the top left of the circuit. The green wires are ground. Other coloured wires are used for signals. The Clock, Latch and Data signals are brought out to a connector which will fit a Digi-ME prototyping board.&lt;/p&gt;

&lt;h2&gt;Selecting Lights&lt;/h2&gt;

&lt;p&gt;Each bit in the value sent to the &lt;b&gt;displayByte&lt;/b&gt; method and then into the shift register will be mapped to a particular chain of lights. The mapping of these is not particularly important, since you can use program constants to represent particular values. I wired the red signals to output pins 4 and 8. To light up just the red lights I used the value 0x88 which is the appropriate bit pattern. I then set up constants for all the other colors:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt; GREEN = 0x11;
&lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt; BLUE = 0x22;
&lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt; YELLOW = 0x44;
&lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt; RED = 0x88;&lt;/pre&gt;

&lt;h2&gt;Setting Up the Hardware&lt;/h2&gt;

&lt;p&gt;The .NET Micro Framework provides a set of classes that can be used to represent the hardware in a system. The program uses instances of the &lt;b&gt;OutputPort&lt;/b&gt; class to represent the output pins. These are created in the method that sets up the hardware:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt; Cpu.Pin clockPin = Cpu.Pin.GPIO_Pin0;
&lt;span class="kwrd"&gt;const&lt;/span&gt; Cpu.Pin dataPin = Cpu.Pin.GPIO_Pin1;
&lt;span class="kwrd"&gt;const&lt;/span&gt; Cpu.Pin latchPin = Cpu.Pin.GPIO_Pin2;

&lt;span class="kwrd"&gt;static&lt;/span&gt; OutputPort clockPort;
&lt;span class="kwrd"&gt;static&lt;/span&gt; OutputPort dataPort;
&lt;span class="kwrd"&gt;static&lt;/span&gt; OutputPort latchPort;

&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; setupOutputs()
{
    clockPort = &lt;span class="kwrd"&gt;new&lt;/span&gt; OutputPort(clockPin, &lt;span class="kwrd"&gt;false&lt;/span&gt;);
    dataPort = &lt;span class="kwrd"&gt;new&lt;/span&gt; OutputPort(dataPin, &lt;span class="kwrd"&gt;false&lt;/span&gt;);
    latchPort = &lt;span class="kwrd"&gt;new&lt;/span&gt; OutputPort(latchPin, &lt;span class="kwrd"&gt;false&lt;/span&gt;);
}&lt;/pre&gt;

&lt;p&gt;In this version of the hardware I have connected pin 0 of the processor to the clock, pin 1 to the data and pin 2 to the latch. If you use different pins you can change the settings above.&lt;/p&gt;

&lt;h1&gt;Software&lt;/h1&gt;

&lt;p&gt;Now that we have working hardware we can consider how the software is to work. Note that this version of the program works correctly but lacks exception handlers that would make it truly robust. I've left these out to simplify the explanation. To make sense of this description you will need to have a copy of the program itself available for reference.&lt;/p&gt;

&lt;p&gt;You can develop the code using Visual Studio 2008 Express edition, which you can download from &lt;a href="http://www.microsoft.com/express/"&gt;http://www.microsoft.com/express/&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The software is written for the .NET Micro Framework 3.0 which you can download from &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=9356ed6f-f1f0-43ef-b21a-4644dd089b4a&amp;amp;displaylang=en"&gt;http://www.microsoft.com/downloads/details.aspx?FamilyID=9356ed6f-f1f0-43ef-b21a-4644dd089b4a&amp;amp;displaylang=en&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;Reading the Blog&lt;/h2&gt;

&lt;p&gt;The program reads the RSS feed from a blog and looks for the &lt;b&gt;&amp;lt;pubDate&amp;gt;&lt;/b&gt; value. This contains the date when the feed was last updated. Whenever this date changes the lights must flash red for a few seconds before resuming a random display. Users of the full .NET Framework can use the &lt;b&gt;HTTPRequest&lt;/b&gt; class to build a &lt;b&gt;GET&lt;/b&gt; command to be sent to a server. Unfortunately the .NET Micro Framework does not support this, so we have to access the web feed using socket based communication. This part of the program is heavily based on the &lt;b&gt;SocketClient&lt;/b&gt; example supplied with the .NET Micro Framework.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// This method requests a page from the specified server.&lt;/span&gt;
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; String GetWebPage(String server, &lt;span class="kwrd"&gt;string&lt;/span&gt; webPage)
{
    &lt;span class="kwrd"&gt;const&lt;/span&gt; Int32 c_httpPort = 80;
    &lt;span class="kwrd"&gt;const&lt;/span&gt; Int32 c_microsecondsPerSecond = 1000000;

    &lt;span class="rem"&gt;// Create a socket connection to the specified server and port.&lt;/span&gt;
    &lt;span class="kwrd"&gt;using&lt;/span&gt; (Socket serverSocket = ConnectSocket(server, c_httpPort))
    {
        &lt;span class="rem"&gt;// Send request to the server.&lt;/span&gt;
        String request = &lt;span class="str"&gt;&amp;quot;GET &amp;quot;&lt;/span&gt;+ webPage + 
             &lt;span class="str"&gt;&amp;quot; HTTP/1.1\r\nHost: &amp;quot;&lt;/span&gt; + server + 
             &lt;span class="str"&gt;&amp;quot;\r\nConnection: Close\r\n\r\n&amp;quot;&lt;/span&gt;;
        Byte[] bytesToSend = Encoding.UTF8.GetBytes(request);
        serverSocket.Send(bytesToSend, bytesToSend.Length, 0);

        &lt;span class="rem"&gt;// Allocate a buffer to receive HTML chunks&lt;/span&gt;
        Byte[] buffer = &lt;span class="kwrd"&gt;new&lt;/span&gt; Byte[1024];

        &lt;span class="rem"&gt;// 'page' refers to the HTML data as it is built up.&lt;/span&gt;
        String page = String.Empty; 

        &lt;span class="rem"&gt;// Wait up to 30 seconds for initial data &lt;/span&gt;
        &lt;span class="rem"&gt;// Will throw exception if connection closed&lt;/span&gt;
        DateTime timeoutAt = DateTime.Now.AddSeconds(30);
        &lt;span class="kwrd"&gt;while&lt;/span&gt; (serverSocket.Available == 0 &amp;amp;&amp;amp; 
               DateTime.Now &amp;lt; timeoutAt)
        {
            System.Threading.Thread.Sleep(100);
        }

        &lt;span class="rem"&gt;// Poll for data until 30 second time out&lt;/span&gt;
        &lt;span class="rem"&gt;// Returns true for data and connection closed&lt;/span&gt;
        &lt;span class="kwrd"&gt;while&lt;/span&gt; (serverSocket.Poll(30 * c_microsecondsPerSecond,
                                 SelectMode.SelectRead))
        {
            &lt;span class="rem"&gt;// Zero all bytes in the re-usable buffer&lt;/span&gt;
            Array.Clear(buffer, 0, buffer.Length);

            &lt;span class="rem"&gt;// Read a buffer-sized HTML chunk&lt;/span&gt;
            Int32 bytesRead = serverSocket.Receive(buffer);

            &lt;span class="rem"&gt;// If 0 bytes in buffer, then connection is closed, &lt;/span&gt;
            &lt;span class="rem"&gt;// or we have timed out&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (bytesRead == 0)
                &lt;span class="kwrd"&gt;break&lt;/span&gt;;

            &lt;span class="rem"&gt;// Append the chunk to the string&lt;/span&gt;
            page += &lt;span class="kwrd"&gt;new&lt;/span&gt; String(Encoding.UTF8.GetChars(buffer));
        }

        &lt;span class="kwrd"&gt;return&lt;/span&gt; page;   &lt;span class="rem"&gt;// Return the complete string&lt;/span&gt;
    }
}&lt;/pre&gt;

&lt;p&gt;This method is called to fetch the journal RSS feed from my blog:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; address = &lt;span class="str"&gt;&amp;quot;www.robmiles.com&amp;quot;&lt;/span&gt;;
&lt;span class="kwrd"&gt;string&lt;/span&gt; name = &lt;span class="str"&gt;&amp;quot;/journal/rss.xml&amp;quot;&lt;/span&gt;;

&lt;span class="kwrd"&gt;string&lt;/span&gt; html = GetWebPage(address, name);&lt;/pre&gt;

&lt;p&gt;You can use it to download from any RSS feed or page on the web. It will throw an exception if the page cannot be read. This version of my program does not perform exception handling however.&lt;/p&gt;

&lt;h2&gt;Getting the Published Date&lt;/h2&gt;

&lt;p&gt;The date is held in the form:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;pubDate&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Wed, 05 Nov 2008 22:38:52 +0000&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;pubDate&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;It would be enough just to record this content and check for changes in the text, but I decided that I might want to use the date information in a later version of the program and so I created some small helper methods to read numbers from the input string and a larger method to read the publish date itself:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; DateTime getRecentPubDate(&lt;span class="kwrd"&gt;string&lt;/span&gt; html, &lt;span class="kwrd"&gt;string&lt;/span&gt; startTag)
{
    &lt;span class="kwrd"&gt;int&lt;/span&gt; index = html.IndexOf(startTag) ;

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (index &amp;lt; 0) 
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;&amp;quot;Missing tag &amp;quot;&lt;/span&gt; + startTag);

    index += startTag.Length;

    &lt;span class="rem"&gt;// spin past the name of the day&lt;/span&gt;
    &lt;span class="kwrd"&gt;while&lt;/span&gt; (index &amp;lt; html.Length &amp;amp;&amp;amp; html[index] != &lt;span class="str"&gt;','&lt;/span&gt;) index++;
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (index == html.Length) 
        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;&amp;quot;Short publish date&amp;quot;&lt;/span&gt;);

    &lt;span class="kwrd"&gt;int&lt;/span&gt; dayValue = getInt(html, &lt;span class="kwrd"&gt;ref&lt;/span&gt; index, &lt;span class="str"&gt;' '&lt;/span&gt;);

    &lt;span class="kwrd"&gt;string&lt;/span&gt; monthName = getString(html, &lt;span class="kwrd"&gt;ref&lt;/span&gt; index, &lt;span class="str"&gt;' '&lt;/span&gt;);
    &lt;span class="kwrd"&gt;int&lt;/span&gt; monthValue = getMonth(monthName);

    &lt;span class="kwrd"&gt;int&lt;/span&gt; yearValue = getInt(html, &lt;span class="kwrd"&gt;ref&lt;/span&gt; index, &lt;span class="str"&gt;' '&lt;/span&gt;);
    &lt;span class="kwrd"&gt;int&lt;/span&gt; hourValue = getInt(html, &lt;span class="kwrd"&gt;ref&lt;/span&gt; index, &lt;span class="str"&gt;':'&lt;/span&gt;);
    &lt;span class="kwrd"&gt;int&lt;/span&gt; minuteValue = getInt(html, &lt;span class="kwrd"&gt;ref&lt;/span&gt; index, &lt;span class="str"&gt;':'&lt;/span&gt;);
    &lt;span class="kwrd"&gt;int&lt;/span&gt; secondValue = getInt(html, &lt;span class="kwrd"&gt;ref&lt;/span&gt; index, &lt;span class="str"&gt;' '&lt;/span&gt;);

    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; DateTime(yearValue, monthValue, dayValue, 
                        hourValue, minuteValue, secondValue);
}&lt;/pre&gt;

&lt;p&gt;The main body of the program uses this method to extract the date out of the RSS feed. When a new date is found it is time to update the lights.&lt;/p&gt;

&lt;h2&gt;Lights and Threads&lt;/h2&gt;

&lt;p&gt;My first version of the program flashed the lights for a while and then checked to see if a new blog post had been made. This worked OK, but the process of loading the RSS feed from the server and checking the dates can take a few seconds, which meant that the flashing lights would freeze every now and then. This did not look very good, and so I decided to use two threads instead. One is in charge of flashing the lights in a random pattern and the other loads the RSS feed from my blog and checks the date of the most recent publication. &lt;/p&gt;

&lt;p&gt;Note that the threading I am using is exactly the same as threading in the full .NET Framework. &lt;/p&gt;

&lt;h2&gt;Thread Communication&lt;/h2&gt;

&lt;p&gt;The two threads communicate by means of a single boolean variable which is set to true when the blog alert is to take place. The display thread reads this flag and flashes the lights red if it is time to alert. &lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; alert = &lt;span class="kwrd"&gt;false&lt;/span&gt;;

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; flasher()
{
    setupOutputs();

    &lt;span class="kwrd"&gt;while&lt;/span&gt; (&lt;span class="kwrd"&gt;true&lt;/span&gt;)
    {
        randomDisplay(400, 10);
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (alert)
        {
            alert = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            flashRed(600, 20);
        }
    }
}&lt;/pre&gt;

&lt;p&gt;The methods &lt;b&gt;randomDisplay&lt;/b&gt; and &lt;b&gt;flashRed&lt;/b&gt; do exactly what you would expect. Each of them gets two numbers to control the lights. The first number gives the delay in milliseconds between flashes (a few hundred milliseconds giving best results). The second gives the number of times that the lights should be flashed before the method finishes. &lt;b&gt;RandomDisplay&lt;/b&gt; displays random colors, whereas &lt;b&gt;flashRed&lt;/b&gt; is simply flashes the red lights. The &lt;b&gt;alert&lt;/b&gt; flag is cleared before the red lights are flashed so that the system will resume normal display after the alert.&lt;/p&gt;

&lt;p&gt;The second thread in the system performs the blog download and date test behaviour. This all happens inside the &lt;b&gt;Main&lt;/b&gt; method:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main()
{
    flashThread = &lt;span class="kwrd"&gt;new&lt;/span&gt; System.Threading.Thread(flasher);

    flashThread.Start();

    &lt;span class="kwrd"&gt;string&lt;/span&gt; address = &lt;span class="str"&gt;&amp;quot;www.robmiles.com&amp;quot;&lt;/span&gt;;
    &lt;span class="kwrd"&gt;string&lt;/span&gt; name = &lt;span class="str"&gt;&amp;quot;/journal/rss.xml&amp;quot;&lt;/span&gt;;

    String html = GetWebPage(address, name);

    DateTime lastUpdate = getRecentPubDate(html, &lt;span class="str"&gt;&amp;quot;&amp;lt;pubDate&amp;gt;&amp;quot;&lt;/span&gt;);

    Debug.Print(&lt;span class="str"&gt;&amp;quot;Initial Update Value : &amp;quot;&lt;/span&gt; + lastUpdate.ToString());

    &lt;span class="kwrd"&gt;while&lt;/span&gt; (&lt;span class="kwrd"&gt;true&lt;/span&gt;)
    {
        System.Threading.Thread.Sleep(10000);

        html = GetWebPage(address, name);

        DateTime blogUpdate = getRecentPubDate(html, &lt;span class="str"&gt;&amp;quot;&amp;lt;pubDate&amp;gt;&amp;quot;&lt;/span&gt;);

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!blogUpdate.Equals(lastUpdate))
        {
            Debug.Print(&lt;span class="str"&gt;&amp;quot;Updated at : &amp;quot;&lt;/span&gt; + blogUpdate.ToString());
            lastUpdate = blogUpdate;
            alert = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        }
    }
}&lt;/pre&gt;

&lt;p&gt;To reduce the load on the network the system only checks the blog feed every 10 seconds.&lt;/p&gt;

&lt;h1&gt;Future Work&lt;/h1&gt;

&lt;p&gt;The program itself works fine, but the error handling is not wonderful. Although some of the methods used throw exceptions these are not caught anywhere, causing the blog reading thread to terminate. This does not stop the lights flashing, but it does mean that there will be no more alerts. However, it is not too hard to create a version which contains proper error handling and even flashes the lights different colors to indicate the alarm conditions. I have created a version that flashes the lights yellow every now and then if the network connection fails. There is also considerable scope for reading other web based sources and changing the output accordingly. Feel free to do all these things and make sure that you have fun.&lt;/p&gt;

&lt;h2&gt;Thanks&lt;/h2&gt;

&lt;p&gt;Thanks go to Ian Mitchell of Ormston Technology (&lt;a href="http://www.ormtec.co.uk/"&gt;http://www.ormtec.co.uk/&lt;/a&gt;) for doing such a great job of hardware design and build.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9149635" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/home+automation/default.aspx">home automation</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/robotics/default.aspx">robotics</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/hardware/default.aspx">hardware</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/hardwarehacks/default.aspx">hardwarehacks</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/holiday/default.aspx">holiday</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/.NET+Microframework/default.aspx">.NET Microframework</category></item><item><title>Stall Status: Know before you go</title><link>http://blogs.msdn.com/coding4fun/archive/2008/08/13/8859880.aspx</link><pubDate>Wed, 13 Aug 2008 21:03:27 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8859880</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/8859880.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=8859880</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=8859880</wfw:comment><description>&lt;span id="c4fmetadata"&gt;   &lt;table cellspacing="0" cellpadding="1" width="100%" border="0"&gt;&lt;tbody&gt;       &lt;tr class="entry_overview"&gt;         &lt;td width="50"&gt;&amp;#160;&lt;a href="http://www.coding4fun.net/images/StallStatusKnowwhentogo_95B7/icon.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="85" alt="icon" src="http://www.coding4fun.net/images/StallStatusKnowwhentogo_95B7/icon_thumb.png" width="75" border="0" /&gt;&lt;/a&gt; &lt;/td&gt;          &lt;td&gt;&lt;span class="entry_description"&gt;Stall Status is a Silverlight-based Vista Sidebar Gadget that uses the Z-Wave wireless protocol and door sensors to notify you of the occupied/available state of the bathroom stalls.&lt;/span&gt;&lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td colspan="2"&gt;           &lt;div class="entry_author"&gt;Jerry Brunning&lt;/div&gt;            &lt;div class="entry_company"&gt;&lt;a href="http://www.claritycon.com"&gt;Clarity Consulting, Inc&lt;/a&gt;&lt;/div&gt;            &lt;br /&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Difficulty: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Easy&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Time Required:&lt;/b&gt; &lt;span class="entry_details_input"&gt;1-3 hours&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Cost: &lt;/b&gt;&lt;span class="entry_details_input"&gt;$50-$100&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Software: &lt;/b&gt;&lt;span class="entry_details_input"&gt;&lt;a href="http://www.microsoft.com/express/"&gt;Visual C# Express Edition&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Hardware: &lt;/b&gt;&lt;span class="entry_details_input"&gt;&lt;a href="http://www.controlthink.com/zwavesdk.htm"&gt;ControlThink Z-Wave SDK&lt;/a&gt;,&amp;#160; &lt;a href="http://www.amazon.com/Hawking-HRDS1-HomeRemote-Wireless-Window/dp/B0012W9EUW/ref=sr_1_1?ie=UTF8&amp;amp;s=electronics&amp;amp;qid=1218645148&amp;amp;sr=8-1"&gt;Hawking Technologies Z-Wave HRDS1 door sensor&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Download: &lt;/b&gt;&lt;a href="http://employees.claritycon.com/jbrunning/stallstatus/stallstatus_src.zip"&gt;Download&lt;/a&gt;               &lt;ul&gt;&lt;/ul&gt;           &lt;/div&gt;         &lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/span&gt;  &lt;h2&gt;Stall Status &lt;/h2&gt;  &lt;p&gt;Every now and then someone throws out an idea for a completely off-the-wall application that just has to be built. When Jon Rauschenberger, Clarity&amp;#8217;s CTO, came into my office with his &amp;#8220;brilliant idea&amp;#8221; for a monitoring system to track the &amp;#8220;occupied/available&amp;#8221; state of our washroom stalls, I immediately recognized it as one of those moments. I had been doing some research on the Z-Wave wireless protocol for a client project earlier that week, and I thought &amp;#8220;Stall Status&amp;#8221; would be a fun way to get some hands on experience using Z-Wave.&lt;/p&gt;  &lt;p&gt;In this article I will walk you through how to write managed code that interacts with Z-Wave devices. I&amp;#8217;ll also show how to use Silverlight 2.0&amp;#8217;s access policies to write &amp;#8220;connected clients&amp;#8221;: client applications that establish a persistent TCP connection to a remote server and thereby avoid having to poll the server for status changes. Finally, I&amp;#8217;ll walk through the steps necessary to deploy a Silverlight 2.0 application as a Windows Vista Sidebar Gadget.&lt;/p&gt;  &lt;h3&gt;&lt;b&gt;What is Z-Wave?&lt;/b&gt;&lt;/h3&gt;  &lt;p&gt;Z-Wave is a wireless communication protocol that works over radio frequency and is specifically designed for low-power, low-bandwidth usage scenarios. Typical usage scenarios for Z-Wave devices are monitoring and control applications &amp;#8211; such as home automation. Available devices include door sensors, switches, and motors. Z-Wave devices are interoperable - devices labeled as Z-Wave compliant should all work together.&lt;/p&gt;  &lt;p&gt;A Z-Wave network consists of one or more devices and a centralized controller. A controller can be a standalone (often hand held) hardware unit or a software-based kit. Devices on a Z-Wave network handle the routing of messages automatically without the need to set up pre-defined routes. This means that if you have several devices in your network that need to communicate together (e.g. a door sensor and an alarm), the devices can route messages through each other. This &amp;#8220;mesh&amp;#8221; communication capability allows you to extend the range of your network much farther than you would be able to if the devices all required direct connections to each other.&amp;#160; For example, if you have three devices, A, B and C, device A can communicate with device C, even if C is outside of A's range, by routing its messages through device B.&amp;#160; This all works automatically.&lt;/p&gt;  &lt;p&gt;My simple Z-Wave network for Stall Status consists of door sensors to notify me when a stall door is opened and closed, and a software based controller. I used Hawking Technologies&amp;#8217; HRDS1 battery powered door sensors for each stall door in the washroom. The HRDS1 is considered an &amp;#8220;occasionally on&amp;#8221; device &amp;#8211; it quietly sits in sleep mode until it detects an open/close event from the door. This is the same type of device you would use, for example, when building an alarm system for monitoring windows and doors.&amp;#160; For the Z-Wave controller I used an excellent software-based controller and SDK from &lt;a href="http://www.controlthink.com/"&gt;ControlThink&lt;/a&gt;, which you can purchase for $70. The controller consists of a USB dongle and a set of APIs for connecting to and communicating with devices. ControlThink includes a number of .Net sample applications, but be warned that the sample applications are not device specific, and the available devices usually assume you are integrating them into an existing hardware-controlled environment, so the documentation surrounding their usage tends to be sparse.&lt;/p&gt;  &lt;p&gt;Using the ControlThink SDK is very straight forward. You simply plug in the USB dongle, reference their DLL from your .Net application, and connect to the controller with a single line of code. Once connected, you can manage your network by adding devices, removing devices, iterating the list of devices, etc. &lt;/p&gt;  &lt;p&gt;I ended up writing three applications to support Stall Status:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;An administrative application for adding/removing/listing the Z-Wave devices on my network.&amp;#160; This is called StallStatusAdmin.&lt;/li&gt;    &lt;li&gt;A Windows Service to listen for open/close events from the door sensors and notify any connected client.&amp;#160; This is called StallStatusController.&lt;/li&gt;    &lt;li&gt;A Silverlight 2.0 client application (the end-user interface) that connects to the Windows Service to receive event notifications.&amp;#160; This is called StallStatusSilverlight.&lt;/li&gt; &lt;/ol&gt;  &lt;h3&gt;&lt;b&gt;Setting up the Z-Wave network&lt;/b&gt;&lt;/h3&gt;  &lt;p&gt;The administration application is a simple Windows Forms EXE that allows me to manage the network by adding, removing and listing the devices. This is simple to do using the ControlThink SDK &amp;#8211; in most cases involving just a couple lines of code. Each Z-Wave device has some mechanism to put the device into &amp;#8220;programming mode&amp;#8221; . The HRDS1 has a button on the back that when pressed, puts the device into programming mode and allows the device to accept programming codes from the controller.&lt;/p&gt;  &lt;p&gt;Listing 1 shows how to add a device to the network. Adding a device consists of registering the device with the controller, and then creating a relationship between the controller and the device's association group to enable the device to route messages to the controller. Once a device is registered, the controller assigns a unique NodeID that we will use to differentiate the three sensors from each other.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;&lt;font size="2"&gt;C#&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;  &lt;pre class="csharpcode"&gt;ZWaveController controller = Connect(); 
MessageBox.Show(&lt;span class="str"&gt;&amp;quot;After pressing OK, press the \&amp;quot;programming\&amp;quot; button on your device.&amp;quot;&lt;/span&gt;);
ZWaveDevice device = controller.AddDevice();
            
device.Groups[1].Clear();
device.Groups[1].Add(controller.Devices.GetByNodeID(controller.NodeID));&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;em&gt;VB.Net&lt;/em&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;Dim&lt;/span&gt; controller &lt;span class="kwrd"&gt;As&lt;/span&gt; ZWaveController = Connect()
MessageBox.Show(&lt;span class="str"&gt;&amp;quot;After pressing OK, press the &amp;quot;&lt;/span&gt;&lt;span class="str"&gt;&amp;quot;programming&amp;quot;&lt;/span&gt;&lt;span class="str"&gt;&amp;quot; button on your device.&amp;quot;&lt;/span&gt;)
&lt;span class="kwrd"&gt;Dim&lt;/span&gt; device &lt;span class="kwrd"&gt;As&lt;/span&gt; ZWaveDevice = controller.AddDevice()

device.Groups(1).Clear()
device.Groups(1).Add(controller.Devices.GetByNodeID(controller.NodeID))&lt;/pre&gt;

&lt;p&gt;&lt;i&gt;Listing 1 &amp;#8211; Adding a device to the network.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Getting a list of the registered devices on the network is as easy a iterating through the Devices collection on the controller.&lt;/p&gt;

&lt;p&gt;&lt;span class="kwrd"&gt;&lt;font size="2"&gt;&lt;em&gt;C#&lt;/em&gt;&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; result = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
ZWaveController controller = Connect();

&lt;span class="kwrd"&gt;if&lt;/span&gt; (controller.Devices.Count &amp;gt; 0) {
   &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (ZWaveDevice d &lt;span class="kwrd"&gt;in&lt;/span&gt; controller.Devices)    {
    result += d.GetType().ToString() + &lt;span class="str"&gt;&amp;quot; as Node #&amp;quot;&lt;/span&gt; + d.NodeID + &lt;span class="str"&gt;&amp;quot; PollEnabled = &amp;quot;&lt;/span&gt; + d.PollEnabled + &lt;span class="str"&gt;&amp;quot;\r\n&amp;quot;&lt;/span&gt;;
   }
}
&lt;span class="kwrd"&gt;else &lt;/span&gt;{
   result = &lt;span class="str"&gt;&amp;quot;No devices found on the network&amp;quot;&lt;/span&gt;;                
}
MessageBox.Show(result);&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&lt;em&gt;&lt;font color="#000000"&gt;VB.Net&lt;/font&gt;&lt;/em&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;Dim&lt;/span&gt; result &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="kwrd"&gt;Dim&lt;/span&gt; controller &lt;span class="kwrd"&gt;As&lt;/span&gt; ZWaveController = Connect()

&lt;span class="kwrd"&gt;If&lt;/span&gt; controller.Devices.Count &amp;gt; 0 &lt;span class="kwrd"&gt;Then&lt;/span&gt;
   &lt;span class="kwrd"&gt;For&lt;/span&gt; &lt;span class="kwrd"&gt;Each&lt;/span&gt; d &lt;span class="kwrd"&gt;As&lt;/span&gt; ZWaveDevice &lt;span class="kwrd"&gt;In&lt;/span&gt; controller.Devices
    result &amp;amp;= d.&lt;span class="kwrd"&gt;GetType&lt;/span&gt;().ToString() &amp;amp; &lt;span class="str"&gt;&amp;quot; as Node #&amp;quot;&lt;/span&gt; &amp;amp; d.NodeID &amp;amp; &lt;span class="str"&gt;&amp;quot; PollEnabled = &amp;quot;&lt;/span&gt; &amp;amp; d.PollEnabled &amp;amp; Constants.vbCrLf
   &lt;span class="kwrd"&gt;Next&lt;/span&gt; d
&lt;span class="kwrd"&gt;Else&lt;/span&gt;
   result = &lt;span class="str"&gt;&amp;quot;No devices found on the network&amp;quot;&lt;/span&gt;
&lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;
MessageBox.Show(result)&lt;/pre&gt;
&lt;style type="text/css"&gt;





.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;i&gt;Listing 2 &amp;#8211; Listing the devices in the network.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;

&lt;h3&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;

&lt;h3&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;

&lt;h3&gt;&lt;b&gt;Receiving Z-Wave Events&lt;/b&gt;&lt;/h3&gt;

&lt;p&gt;Once the devices are registered on the network, they will send event notifications back to the controller each time the sensor is triggered. The next steps for us are to write code to receive the events and forward them to any client applications that are connected. To do this we&amp;#8217;ll write a Windows Service that listens for events from the sensors.&lt;/p&gt;

&lt;p&gt;All of the work for listening for events from the Z-Wave devices is handled for us by the ControlThink SDK. We simply connect to the controller and sink the LevelChanged event. We do this in our Run method, which is called from within our service&amp;#8217;s OnStart function.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&lt;em&gt;&lt;font color="#000000"&gt;C#&lt;/font&gt;&lt;/em&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Run() {
   &lt;span class="kwrd"&gt;try&lt;/span&gt;  {
       _controller = &lt;span class="kwrd"&gt;new&lt;/span&gt; ZWaveController();
       &lt;span class="kwrd"&gt;try&lt;/span&gt;  {
          _controller.Connect();
       }
       &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex) {
          &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Exception(&lt;span class="str"&gt;&amp;quot;Unable to connect.\r\n&amp;quot;&lt;/span&gt; + ex.ToString());
       }

       _controller.LevelChanged += &lt;span class="kwrd"&gt;new&lt;/span&gt; ZWaveController.LevelChangedEventHandler(_controller_LevelChanged);

       _policyListener = &lt;span class="kwrd"&gt;new&lt;/span&gt; PolicyListener();
       _listener = &lt;span class="kwrd"&gt;new&lt;/span&gt; SocketListener();
       _listener.Port = 4530;
             
        &lt;span class="kwrd"&gt;new&lt;/span&gt; System.Threading.Thread(&lt;span class="kwrd"&gt;new&lt;/span&gt; System.Threading.ThreadStart(_listener.StartSocketServer)).Start();
        &lt;span class="kwrd"&gt;new&lt;/span&gt; System.Threading.Thread(&lt;span class="kwrd"&gt;new&lt;/span&gt; System.Threading.ThreadStart(_policyListener.StartSocketServer)).Start();
        &lt;span class="kwrd"&gt;new&lt;/span&gt; System.Threading.Thread(&lt;span class="kwrd"&gt;new&lt;/span&gt; System.Threading.ThreadStart(ClearRecent)).Start();
   }
   &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex) {
       Logger.WriteException(ex);
   }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;em&gt;&lt;font size="2"&gt;VB.Net&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; Run()
   &lt;span class="kwrd"&gt;Try&lt;/span&gt;
       _controller = &lt;span class="kwrd"&gt;New&lt;/span&gt; ZWaveController()
       &lt;span class="kwrd"&gt;Try&lt;/span&gt;
          _controller.Connect()
       &lt;span class="kwrd"&gt;Catch&lt;/span&gt; ex &lt;span class="kwrd"&gt;As&lt;/span&gt; Exception
          &lt;span class="kwrd"&gt;Throw&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; Exception(&lt;span class="str"&gt;&amp;quot;Unable to connect.&amp;quot;&lt;/span&gt; &amp;amp; Constants.vbCrLf &amp;amp; ex.ToString())
       &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Try&lt;/span&gt;

       &lt;span class="kwrd"&gt;AddHandler&lt;/span&gt; _controller.LevelChanged, &lt;span class="kwrd"&gt;AddressOf&lt;/span&gt; _controller_LevelChanged

       _policyListener = &lt;span class="kwrd"&gt;New&lt;/span&gt; PolicyListener()
       _listener = &lt;span class="kwrd"&gt;New&lt;/span&gt; SocketListener()
       _listener.Port = 4530

        &lt;span class="kwrd"&gt;CType&lt;/span&gt;(&lt;span class="kwrd"&gt;New&lt;/span&gt; System.Threading.Thread(&lt;span class="kwrd"&gt;New&lt;/span&gt; System.Threading.ThreadStart(&lt;span class="kwrd"&gt;AddressOf&lt;/span&gt; _listener.StartSocketServer)), System.Threading.Thread).Start()
        &lt;span class="kwrd"&gt;CType&lt;/span&gt;(&lt;span class="kwrd"&gt;New&lt;/span&gt; System.Threading.Thread(&lt;span class="kwrd"&gt;New&lt;/span&gt; System.Threading.ThreadStart(&lt;span class="kwrd"&gt;AddressOf&lt;/span&gt; _policyListener.StartSocketServer)), System.Threading.Thread).Start()
        &lt;span class="kwrd"&gt;CType&lt;/span&gt;(&lt;span class="kwrd"&gt;New&lt;/span&gt; System.Threading.Thread(&lt;span class="kwrd"&gt;New&lt;/span&gt; System.Threading.ThreadStart(&lt;span class="kwrd"&gt;AddressOf&lt;/span&gt; ClearRecent)), System.Threading.Thread).Start()
   &lt;span class="kwrd"&gt;Catch&lt;/span&gt; ex &lt;span class="kwrd"&gt;As&lt;/span&gt; Exception
       Logger.WriteException(ex)
   &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Try&lt;/span&gt;
&lt;span class="kwrd"&gt;End&lt;/span&gt; Sub&lt;/pre&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;i&gt;Listing 3 &amp;#8211; Listening for Z-Wave events when our service starts up.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;In addition to listening for events from the ZWave Controller, our Run method also sets up socket listeners for talking to the Silverlight client application, which we will talk about later. An important detail to note, however, is the use of threading in the Run method. Remember that this is called directly from our service&amp;#8217;s OnStart code which we should not block - if you block OnStart, you&amp;#8217;ll see the service stuck at &amp;#8220;Starting...&amp;#8221; in the Service Control Manager. Anything that will block or that is long running (such as a socket listener) needs to run on a separate thread.&lt;/p&gt;

&lt;p&gt;When the controller detects that one of the sensors has changed its state, it throws the LevelChanged event to our service. Our service handles LevelChanged in the _controller_LevelChanged method. The signature for the LevelChanged event looks like this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; _controller_LevelChanged(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, ZWaveController.LevelChangedEventArgs e)&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;The LevelChangeEventArgs contains the original device that raised the event. We have three door sensors connected to our network. When any of them are triggered, LevelChanged is raised and we can inspect the LevelChangedEventArgs to get the NodeID of the unique identifier of the device. That&amp;#8217;s all there is to interacting with the Z-Wave network.&lt;/p&gt;

&lt;h2&gt;Silverlight 2.0&lt;/h2&gt;

&lt;p&gt;Now that we&amp;#8217;ve got the server infrastructure set up it is time to build a client application so we can actually start using Stall Status. I built the client application in Silverlight as an exercise to show how to use Silverlight 2.0&amp;#8217;s access policy to make cross domain network calls from a Silverlight client application. I also knew that it is simple to deploy a Silverlight application as a Windows Vista Gadget, and the Sidebar was to be my preferred deployment model for the application.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/StallStatusKnowwhentogo_95B7/StallStatus2.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="149" alt="StallStatus2" src="http://www.coding4fun.net/images/StallStatusKnowwhentogo_95B7/StallStatus2_thumb.png" width="131" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;i&gt;Figure 1 &amp;#8211; Stall Status interface&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;The main UI for the application is pretty simple &amp;#8211; three ellipses, one for each stall, colored green if the stall is available and red if the stall is occupied. Most of the challenge with building the client piece has to do with connecting to the service and listening for updates. To do this, we create a persistent TCP connection and wait for data to be sent from the service over the socket. This is much better than a polling approach for an application like this because of the way the Z-Wave door sensors work. They are in sleep mode most of the time, and are only using power when they transmit a signal due to the door opening or closing. If we polled the devices frequently, it would kill the batteries in the device. Also, most of the time there is no change to the state of the doors, so polling would really be a waste.&lt;/p&gt;

&lt;p&gt;Silverlight contains certain security mechanisms around network connectivity, especially TCP sockets. This is due to the fact that a Silverlight application runs in the context of the user&amp;#8217;s browser, so special controls need to be in place to limit the type of connectivity that Silverlight applications can initiate. For socket-based connections, Silverlight 2.0 requires an access policy to be in place on the target server. This access policy essentially is a challenge/response mechanism that prevents a Silverlight application from connecting to an arbitrary server, potentially masquerading as the end user.&lt;/p&gt;

&lt;h3&gt;Access Policy&lt;/h3&gt;

&lt;p&gt;An Access Policy must be in place on the server for in order to enable a Silverlight 2.0 client to connect using sockets. The Silverlight framework handles all of the validation for the presence of the access policy, so your client application does not need to do anything. However, if the proper policy is not in place on the target server, Silverlight will throw an Access Denied exception, so your client application should be prepared to handle this situation. This is all very similar to how network access in Flash applications work. In fact, Silverlight can consume Flash policy files directly, as well as Silverlight policy files. In the Stall Status application, we&amp;#8217;re going to be using Silverlight policy.&lt;/p&gt;

&lt;p&gt;When a Silverlight application attempts to open a socket to a target server, Silverlight will automatically look for an access policy on the server by establishing a TCP connection over port 943, and sending a policy request. The policy request is simply an XML-style string: &amp;lt;policy-file-request/&amp;gt;. It is up to the author of the service that is receiving the request to ensure that they properly respond to this request, or else Silverlight will raise an exception on the client. All of this is described in detail in the &lt;a href="http://msdn.microsoft.com/en-us/library/cc645032(VS.95).aspx"&gt;MSDN documentation&lt;/a&gt; on the new network security restrictions in Silverlight 2.0.&lt;/p&gt;

&lt;p&gt;In order to respond to a request for an access policy on our server, we need to implement a network listener on port 943 that responds to Silverlight&amp;#8217;s policy file request. &lt;a href="http://weblogs.asp.net/dwahlin/archive/2008/04/10/pushing-data-to-a-silverlight-client-with-sockets-part-i.aspx"&gt;Dan Wahlin&lt;/a&gt; wrote a multi-part blog post showing exactly how to do this, and the listener I used for Stall Status, plus much of the other socket code, is copied from his example. I recommend reading his post - it is a great primer on writing TCP socket clients in Silverlight 2.0.&lt;/p&gt;

&lt;p&gt;Our listener class run in our windows service and simply sets up a listener on port 943. When it receives a policy file request, it returns the appropriate response, as shown below.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt; &lt;span class="kwrd"&gt;=&amp;quot;utf-8&amp;quot;&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;access-policy&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;cross-domain-access&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;policy&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;allow-from&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;domain&lt;/span&gt; &lt;span class="attr"&gt;uri&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;*&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;allow-from&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;grant-to&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;socket-resource&lt;/span&gt; &lt;span class="attr"&gt;port&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;4530&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;protocol&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;tcp&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;grant-to&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;policy&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;cross-domain-access&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;access-policy&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;This response tells Silverlight to allow incoming connections to port 4530, which is the port that our service is listening on to accept connections from our Silverlight client.&lt;/p&gt;

&lt;p&gt;Why is this important? Well, without access policy in place, there is nothing that prevents a malicious Silverlight application from connecting to a server without permission. For example:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Suppose you have an active session with your online bank. A malicious Silverlight application served up from Site A could attempt to connect to your bank using your existing login token (which may be stored as a cookie). With access policy in place, your bank would need to have a policy stating that it allowed Silverlight applications originating from Site A to connect to your bank. &lt;/li&gt;

  &lt;li&gt;Suppose you connect to Site A and download a malicious Silverlight application. The application can potentially connect to your corporate intranet and because you are on a corporate domain, the Silverlight app impersonates you. With the access policy rules in place, this would be prevented. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Persistent client connections&lt;/h3&gt;

&lt;p&gt;Now that we&amp;#8217;ve got our access policy in place, we&amp;#8217;re ready to code up our Silverlight client to connect to our server and wait for updates. Silverlight 2.0 can only connect using sockets over the port range 4502-4534. Our Windows Service uses 4530. It creates a listener on this port and then sits and waits for connections from our Silverlight clients.&lt;/p&gt;

&lt;p&gt;&lt;font size="2"&gt;C#&lt;/font&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;_listener = &lt;span class="kwrd"&gt;new&lt;/span&gt; TcpListener(IPAddress.Any, Port);
_listener.Start();
&lt;span class="kwrd"&gt;while&lt;/span&gt; (&lt;span class="kwrd"&gt;true&lt;/span&gt;)
{
   _waitEvent.Reset();
   _listener.BeginAcceptTcpClient(&lt;span class="kwrd"&gt;new&lt;/span&gt; AsyncCallback(OnBeginAccept), &lt;span class="kwrd"&gt;null&lt;/span&gt;);
   _waitEvent.WaitOne();
}&lt;/pre&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;em&gt;&lt;font size="2"&gt;VB.Net&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;_listener = &lt;span class="kwrd"&gt;New&lt;/span&gt; TcpListener(IPAddress.Any, Port)
_listener.Start()
&lt;span class="kwrd"&gt;Do&lt;/span&gt;
   _waitEvent.Reset()
   _listener.BeginAcceptTcpClient(&lt;span class="kwrd"&gt;New&lt;/span&gt; AsyncCallback(&lt;span class="kwrd"&gt;AddressOf&lt;/span&gt; OnBeginAccept), &lt;span class="kwrd"&gt;Nothing&lt;/span&gt;)
   _waitEvent.WaitOne()
&lt;font color="#0000ff"&gt;Loop&lt;/font&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;i&gt;Listing 4 &amp;#8211; Our main listener for client connections&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;We&amp;#8217;re using asynchronous sockets, so we&amp;#8217;ve set up a delegate &amp;#8211; OnBeginAccept &amp;#8211; to accept and process our connections. The code to process the connects is listed below.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;font size="2"&gt;C#&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;_waitEvent.Set();
TcpListener listener = _listener;
TcpClient client = listener.EndAcceptTcpClient(ar);

&lt;span class="kwrd"&gt;if&lt;/span&gt; (client.Connected)
{
   Logger.WriteLine(&lt;span class="str"&gt;&amp;quot;Accepted a connection from &amp;quot;&lt;/span&gt; + client.Client.RemoteEndPoint.ToString());

   StreamWriter writer = &lt;span class="kwrd"&gt;new&lt;/span&gt; StreamWriter(client.GetStream());
   writer.AutoFlush = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
   _clients.Add(writer);
   writer.WriteLine(&lt;span class="str"&gt;&amp;quot;Connected.&amp;quot;&lt;/span&gt;);

   &lt;span class="kwrd"&gt;if&lt;/span&gt; (ClientConnected != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
   {
     ClientConnected(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;);
   }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;&lt;em&gt;&lt;font size="2"&gt;VB.Net&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;_waitEvent.&lt;span class="kwrd"&gt;Set&lt;/span&gt;()
&lt;span class="kwrd"&gt;Dim&lt;/span&gt; listener &lt;span class="kwrd"&gt;As&lt;/span&gt; TcpListener = _listener
&lt;span class="kwrd"&gt;Dim&lt;/span&gt; client &lt;span class="kwrd"&gt;As&lt;/span&gt; TcpClient = listener.EndAcceptTcpClient(ar)

&lt;span class="kwrd"&gt;If&lt;/span&gt; client.Connected &lt;span class="kwrd"&gt;Then&lt;/span&gt;
   Logger.WriteLine(&lt;span class="str"&gt;&amp;quot;Accepted a connection from &amp;quot;&lt;/span&gt; &amp;amp; client.Client.RemoteEndPoint.ToString())

   &lt;span class="kwrd"&gt;Dim&lt;/span&gt; writer &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;New&lt;/span&gt; StreamWriter(client.GetStream())
   writer.AutoFlush = &lt;span class="kwrd"&gt;True&lt;/span&gt;
   _clients.Add(writer)
   writer.WriteLine(&lt;span class="str"&gt;&amp;quot;Connected.&amp;quot;&lt;/span&gt;)

   &lt;span class="kwrd"&gt;If&lt;/span&gt; ClientConnected IsNot &lt;span class="kwrd"&gt;Nothing&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;
     ClientConnected(&lt;span class="kwrd"&gt;Me&lt;/span&gt;, &lt;span class="kwrd"&gt;Nothing&lt;/span&gt;)
   &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;
&lt;span class="kwrd"&gt;End&lt;/span&gt; If&lt;/pre&gt;

&lt;p&gt;&lt;i&gt;Listing 5 &amp;#8211; Accepting a new client connection&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Here we are simply adding a StreamWriter for each connected client to a List. We do this so when we receive events from the door sensors, we can loop through this List and notify all of the clients. We notify them by writing a tokenized string to the StreamWriter. We also have code to remove any clients from the list if we fail to write to their stream. This way we can catch the situation where the client disconnected.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&lt;em&gt;&lt;font color="#000000"&gt;C#&lt;/font&gt;&lt;/em&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i=_clients.Count-1;i&amp;gt;=0;i--)
{
   &lt;span class="kwrd"&gt;try&lt;/span&gt;
   {
      _clients[i].WriteLine(eventText);
   }
   &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
   {
      Logger.WriteException(ex);
      Logger.WriteLine(&lt;span class="str"&gt;&amp;quot;Removing client # &amp;quot;&lt;/span&gt; + i + &lt;span class="str"&gt;&amp;quot; because we failed to send them data.&amp;quot;&lt;/span&gt;);
      _clients.Remove(_clients[i]);
   }
}&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;VB.Net&lt;/em&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;For&lt;/span&gt; i &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = _clients.Count-1 &lt;span class="kwrd"&gt;To&lt;/span&gt; 0 &lt;span class="kwrd"&gt;Step&lt;/span&gt; -1
   &lt;span class="kwrd"&gt;Try&lt;/span&gt;
      _clients(i).WriteLine(eventText)
   &lt;span class="kwrd"&gt;Catch&lt;/span&gt; ex &lt;span class="kwrd"&gt;As&lt;/span&gt; Exception
      Logger.WriteException(ex)
      Logger.WriteLine(&lt;span class="str"&gt;&amp;quot;Removing client # &amp;quot;&lt;/span&gt; &amp;amp; i &amp;amp; &lt;span class="str"&gt;&amp;quot; because we failed to send them data.&amp;quot;&lt;/span&gt;)
      _clients.Remove(_clients(i))
   &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Try&lt;/span&gt;
&lt;span class="kwrd"&gt;Next&lt;/span&gt; i&lt;/pre&gt;

&lt;p&gt;&lt;i&gt;Listing 6 &amp;#8211; Sending an update to all clients&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;The text we pass to each client (represented in the code above by the eventText variable) is simply the NodeID of the sensor that triggered the event and the state (open/closed) on the sensor. The Silverlight client receives this text, parses it out, and updates the color of the ellipse accordingly.&lt;/p&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&lt;em&gt;&lt;font color="#000000"&gt;C#&lt;/font&gt;&lt;/em&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; UpdateText(&lt;span class="kwrd"&gt;string&lt;/span&gt; text)
{
    &lt;span class="kwrd"&gt;string&lt;/span&gt;[] parts = text.Split(&lt;span class="str"&gt;' '&lt;/span&gt;);

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (parts.Length != 2) {
        &lt;span class="kwrd"&gt;return&lt;/span&gt;;
    }

    &lt;span class="kwrd"&gt;int&lt;/span&gt; stallNumber = Convert.ToInt32(parts[0]);
    &lt;span class="kwrd"&gt;string&lt;/span&gt; status = parts[1].ToLower();

    StatusIndicator thisStall = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    &lt;span class="kwrd"&gt;switch&lt;/span&gt; (stallNumber) {
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 1:
            thisStall = &lt;span class="kwrd"&gt;this&lt;/span&gt;.Stall1;
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        &lt;span class="kwrd"&gt;case&lt;/span&gt; 2:
            thisStall = &lt;span class="kwrd"&gt;this&lt;/span&gt;.Stall2;
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        &lt;span class="kwrd"&gt;default&lt;/span&gt;:
            thisStall = &lt;span class="kwrd"&gt;this&lt;/span&gt;.Stall3;
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
    }

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (status.Trim() == &lt;span class="str"&gt;&amp;quot;open&amp;quot;&lt;/span&gt;) {
        thisStall.Status = StallStatus.Open;
    }
    &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (status.Trim() == &lt;span class="str"&gt;&amp;quot;closed&amp;quot;&lt;/span&gt;) {
        thisStall.Status = StallStatus.Closed;
    }
    &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (status.Trim() == &lt;span class="str"&gt;&amp;quot;recent&amp;quot;&lt;/span&gt;) {
        thisStall.Status = StallStatus.Recent;
    }
    &lt;span class="kwrd"&gt;else&lt;/span&gt; {
        thisStall.Status = StallStatus.Unknown;
    }
}&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;em&gt;VB.Net&lt;/em&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; UpdateText(&lt;span class="kwrd"&gt;ByVal&lt;/span&gt; text &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt;)
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; parts() &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; = text.Split(&lt;span class="str"&gt;&amp;quot; &amp;quot;&lt;/span&gt;c)

    &lt;span class="kwrd"&gt;If&lt;/span&gt; parts.Length &amp;lt;&amp;gt; 2 &lt;span class="kwrd"&gt;Then&lt;/span&gt;
        &lt;span class="kwrd"&gt;Return&lt;/span&gt;
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;

    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; stallNumber &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;Integer&lt;/span&gt; = Convert.ToInt32(parts(0))
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; status &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt; = parts(1).ToLower()

    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; thisStall &lt;span class="kwrd"&gt;As&lt;/span&gt; StatusIndicator = &lt;span class="kwrd"&gt;Nothing&lt;/span&gt;
    &lt;span class="kwrd"&gt;Select&lt;/span&gt; &lt;span class="kwrd"&gt;Case&lt;/span&gt; stallNumber
        &lt;span class="kwrd"&gt;Case&lt;/span&gt; 1
            thisStall = &lt;span class="kwrd"&gt;Me&lt;/span&gt;.Stall1
        &lt;span class="kwrd"&gt;Case&lt;/span&gt; 2
            thisStall = &lt;span class="kwrd"&gt;Me&lt;/span&gt;.Stall2
        &lt;span class="kwrd"&gt;Case&lt;/span&gt; &lt;span class="kwrd"&gt;Else&lt;/span&gt;
            thisStall = &lt;span class="kwrd"&gt;Me&lt;/span&gt;.Stall3
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;Select&lt;/span&gt;

    &lt;span class="kwrd"&gt;If&lt;/span&gt; status.Trim() = &lt;span class="str"&gt;&amp;quot;open&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;
        thisStall.Status = StallStatus.Open
    &lt;span class="kwrd"&gt;ElseIf&lt;/span&gt; status.Trim() = &lt;span class="str"&gt;&amp;quot;closed&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;
        thisStall.Status = StallStatus.Closed
    &lt;span class="kwrd"&gt;ElseIf&lt;/span&gt; status.Trim() = &lt;span class="str"&gt;&amp;quot;recent&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;Then&lt;/span&gt;
        thisStall.Status = StallStatus.Recent
    &lt;span class="kwrd"&gt;Else&lt;/span&gt;
        thisStall.Status = StallStatus.Unknown
    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;
&lt;span class="kwrd"&gt;End&lt;/span&gt; Sub&lt;/pre&gt;

&lt;p&gt;&lt;i&gt;Listing 7 &amp;#8211; Receiving the update on the client from the server&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;The only other thing the application contains is the concept of &amp;quot;recently occupied&amp;quot;. Once a stall has been vacated, we track it as recently occupied. This shows up on the client application as a yellow ellipse. To do this we keep track of a timestamp whenever the door opens.&amp;#160; Our Service contains a dedicated thread that checks for doors opened more than 2 minutes ago. If it finds any, it changes the door's status from &amp;#8220;Recent&amp;#8221; to a status of &amp;#8220;Opened&amp;#8221;.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&lt;em&gt;&lt;font color="#000000"&gt;C#&lt;/font&gt;&lt;/em&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ClearRecent()
{
  &lt;span class="kwrd"&gt;while&lt;/span&gt; (!_wait.WaitOne(10000,&lt;span class="kwrd"&gt;false&lt;/span&gt;))
  {
    var q = from stall &lt;span class="kwrd"&gt;in&lt;/span&gt; _stalls
      &lt;span class="kwrd"&gt;where&lt;/span&gt; stall.Timestamp.AddMinutes(2) &amp;lt; DateTime.Now &amp;amp;&amp;amp; stall.State.Equals(DoorState.Recent)
      select stall;

    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (Stall stall &lt;span class="kwrd"&gt;in&lt;/span&gt; q)
    {
      &lt;span class="kwrd"&gt;if&lt;/span&gt; (stall.State.Equals(DoorState.Recent)) {
        stall.State = DoorState.Open;
        Broadcast(stall.NodeID, DoorState.Open);
      }
    }
  }
}&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;em&gt;VB.Net&lt;/em&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; ClearRecent()
  &lt;span class="kwrd"&gt;Do&lt;/span&gt; &lt;span class="kwrd"&gt;While&lt;/span&gt; &lt;span class="kwrd"&gt;Not&lt;/span&gt; _wait.WaitOne(10000,&lt;span class="kwrd"&gt;False&lt;/span&gt;)
    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; q = From stall &lt;span class="kwrd"&gt;In&lt;/span&gt; _stalls _
            Where stall.Timestamp.AddMinutes(2) &amp;lt; DateTime.Now &lt;span class="kwrd"&gt;AndAlso&lt;/span&gt; stall.State.Equals(DoorState.Recent) _
            &lt;span class="kwrd"&gt;Select&lt;/span&gt; stall

    &lt;span class="kwrd"&gt;For&lt;/span&gt; &lt;span class="kwrd"&gt;Each&lt;/span&gt; stall &lt;span class="kwrd"&gt;As&lt;/span&gt; Stall &lt;span class="kwrd"&gt;In&lt;/span&gt; q
      &lt;span class="kwrd"&gt;If&lt;/span&gt; stall.State.Equals(DoorState.Recent) &lt;span class="kwrd"&gt;Then&lt;/span&gt;
        stall.State = DoorState.Open
        Broadcast(stall.NodeID, DoorState.Open)
      &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;
    &lt;span class="kwrd"&gt;Next&lt;/span&gt; stall
  &lt;span class="kwrd"&gt;Loop&lt;/span&gt;
&lt;span class="kwrd"&gt;End&lt;/span&gt; Sub&lt;/pre&gt;

&lt;p&gt;&lt;i&gt;Listing 8 &amp;#8211; Clearing the &amp;#8220;recently opened&amp;#8221; flag&lt;/i&gt;&lt;/p&gt;

&lt;h2&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;

&lt;h2&gt;&lt;b&gt;Vista Sidebar Gadget&lt;/b&gt;&lt;/h2&gt;

&lt;p&gt;Once I had the Service and Silverlight client apps written, it was time to deploy the client as a Vista Sidebar Gadget. This is actually pretty simple to do with a Silverlight application, but there are a couple things to work through for 64-bit versions of Vista.&lt;/p&gt;

&lt;p&gt;Packaging a Silverlight application to run as a Gadget is not that different than running it locally or via a web page. You simple collect all of the files for your application, add a manifest file, zip them up, and rename the ZIP file so it has a .gadget file extension.&lt;/p&gt;

&lt;p&gt;One easy way to create the manifest file is to start from an existing file from one of your existing gadgets. You can find your installed gadgets in the folder \Users\&amp;lt;user name&amp;gt;\AppData\Local\Microsoft\Windows Sidebar\Gadgets. Note that by default the AppData folder is hidden. Check the folders of any of your gadgets and you&amp;#8217;ll see that they all contain an gadget.xml file. Copy one of these, open it, and make any changes that you need to. Most of the elements in the file are self explanatory, but for a full explanation, check out &lt;a href="http://www.microsoft.com/technet/scriptcenter/topics/vista/gadgets-pt1.mspx#ENH"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you&amp;#8217;ve got your files and manifest packaged up, you can distribute your gadget. Users can run .gadget files directly in Vista and Vista automatically installs them into the sidebar.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/StallStatusKnowwhentogo_95B7/StallStatusGadget2.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="244" alt="StallStatusGadget2" src="http://www.coding4fun.net/images/StallStatusKnowwhentogo_95B7/StallStatusGadget2_thumb.png" width="164" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;i&gt;Figure 2 &amp;#8211; Stall Status deployed as a Vista Sidebar gadget&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;One note with Silverlight-based gadgets and the 64-bit version of Windows Vista: Since Silverlight is a 32-bit application, you cannot directly host Silverlight-based gadgets in the 64-bit version of Sidebar.exe (which is the running by default on 64-bit Vista). As a work around, you can run the 32-bit version of Sidebar.exe, which is located in the \Program Files (x86)\Windows Sidebar\ folder.&lt;/p&gt;

&lt;p&gt;As we&amp;#8217;ve seen in this article it is easy to use .Net to control a Z-Wave network, and there are tons of creative uses for the technology. Writing network-enabled Silverlight applications has become much more powerful in Silverlight 2.0. And deploying Silverlight-based applications as Vista Sidebar Gadgets is pretty simple.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;style type="text/css"&gt;




.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8859880" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/utility/default.aspx">utility</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/home+automation/default.aspx">home automation</category></item><item><title>Home Automation with Microsoft Robotics Developer Studio 2008</title><link>http://blogs.msdn.com/coding4fun/archive/2008/05/23/8544962.aspx</link><pubDate>Sat, 24 May 2008 09:56:55 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8544962</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>20</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/8544962.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=8544962</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=8544962</wfw:comment><description>&lt;span id="c4fmetadata"&gt;   &lt;table cellspacing="0" cellpadding="1" width="100%" border="0"&gt;&lt;tbody&gt;       &lt;tr class="entry_overview"&gt;         &lt;td width="50"&gt;&lt;/td&gt;          &lt;td&gt;           &lt;p&gt;Typically we think of robots as machines from science fiction or as industrial robots such as those that build and paint cars. In the world of Microsoft Robotics Developer Studio, anything that has sensors and/or actuators can be considered a robot. In this article, we look at an automated house as a robot and apply the Decentralized Software Services model of Microsoft Robotics Studio to implementing some home automation tasks.&lt;/p&gt;         &lt;/td&gt;       &lt;/tr&gt;        &lt;tr&gt;         &lt;td colspan="2"&gt;           &lt;div class="entry_author"&gt;Charles Stacy Harris III&lt;/div&gt;            &lt;br /&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Difficulty: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Intermediate&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Time Required:&lt;/b&gt; &lt;span class="entry_details_input"&gt;6-10 hours&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Cost: &lt;/b&gt;&lt;span class="entry_details_input"&gt;$100-$200 for hardware (Optional, $0 if using only simulation)&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Software: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Visual Studio or Visual Studio Express, Microsoft Robotics Developer Studio 2008 CTP April, &lt;a href="http://www.controlthink.com/zwavesdk.htm"&gt;ControlThink Z-Wave PC SDK&lt;/a&gt; &lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Hardware: &lt;/b&gt;&lt;span class="entry_details_input"&gt;(All Optional) Elk M1G/M1EZ Security and Automation Panel, Z-Wave Dimmer Switches, Z-Wave Controller such as the ControlThink ThinkStick or equivalent.&lt;/span&gt;&lt;/div&gt;            &lt;div class="entry_details"&gt;&lt;b&gt;Download: &lt;/b&gt;&lt;a href="http://www.codeplex.com/houserobot"&gt;Download&lt;/a&gt;               &lt;ul&gt;&lt;/ul&gt;           &lt;/div&gt;         &lt;/td&gt;       &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt; &lt;/span&gt;  &lt;h3&gt;House, Robot&lt;/h3&gt;  &lt;p&gt;Those of you who know me or who have read my previous Coding4Fun article &lt;a href="http://blogs.msdn.com/coding4fun/archive/2007/10/05/5296972.aspx"&gt;Home Automation with Windows Workflow&lt;/a&gt;, know that I’m nuts about home automation. I’m even more passionate about robotics and I’ve wanted to try out some things with Microsoft Robotics Studio since the very first version. Recently I had a long weekend, so I spent a few hours putting together some simple home automation examples using Microsoft Robotics Developer Studio 2008 CTP April. Check out the &lt;a href="http://msdn2.microsoft.com/en-us/robotics/default.aspx"&gt;Microsoft Robotics Developer Center&lt;/a&gt; for details on how to get the CTP.&lt;/p&gt;  &lt;p&gt;The examples in this article duplicate what I did using Windows Workflow in my previous article, but instead use the Decentralized Software Services (DSS) approach of Microsoft Robotics, and Microsoft Visual Programming Language (VPL) for a simple way to write automation tasks. The &lt;a href="http://msdn2.microsoft.com/en-us/robotics/default.aspx"&gt;Microsoft Robotics Developer Center&lt;/a&gt; contains a lot of detailed information about DSS, VPL, and the other technologies found in Microsoft Robotics Developer Studio. For now, let’s just cover some basics. To get further along with the code in this article, you’ll want to check out some of the excellent tutorials presented by the Microsoft Robotics team.&lt;/p&gt;  &lt;h3&gt;Services, Messages, and Ports&lt;/h3&gt;  &lt;p&gt;A DSS Service is the basic component upon which Microsoft Robotics applications are built. In fact, DSS services are a generic construct that can and have been used outside of the context of robotics. DSS services contain state and the service state is manipulated via messages sent to the service on a service port.&lt;/p&gt;  &lt;p&gt;Messages sent to a service are structured .NET classes that may contain a message payload that determines how or even if state will be modified, or what part of a service state should be retrieved. There are also message that do not directly manipulate state, but may have some other side-effects. Services respond to messages such as CREATE, LOOKUP, UPDATE, etc. In addition, you can define messages that extend the semantics of the core messages.&lt;/p&gt;  &lt;p&gt;Ports are the mechanism through which services communicate. Ports accept a set of message types that are defined by the service itself. In addition, ports are also used for outbound communication in situations such as subscribing to event notification from a service.&lt;/p&gt;  &lt;p&gt;Again, there are excellent online resources for learning the details of Microsoft Robotics, DSS, and the underlying technologies for Microsoft Robotics developer Studio. You’ll probably want basic familiarity with the Microsoft Robotics architecture including the Concurrency and Coordination Runtime (CCR) along with the notion of Arbiters and iterators.&lt;/p&gt;  &lt;h3&gt;Robo-Moose&lt;/h3&gt;  &lt;p&gt;The security and automation system in my house is centered on an Elk M1G alarm panel from &lt;a href="http://www.elkproducts.com/index.html"&gt;Elk Products Incorporated&lt;/a&gt; . This panel allows for up to 208 input zones in the form of contact switches, motion sensors, and so on. It also allows for up to 208 outputs, on-board task scripting and many other features. One of the key features for my use is the capability of being able to monitor and control the panel via an Ethernet adaptor. So, my first order of business was to write a DSS service – the ElkService – to communicate with the Elk M1G via sockets. This ElkService exchanges messages with the Elk M1G via an ASCII protocol that is documented &lt;a href="http://www.elkproducts.com/products/m1/m1documentation.htm"&gt;here&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;The code that the ElkService uses to read from the Elk M1G hardware is shown below. Note that the code looks sequential, but is actually asynchronous. The StreamAdapter.Read method sets up a task to do an asynchronous IO operation and the line “yield return (Choice)ioResultPort;” returns this task to the runtime which is iterating over all tasks returned by ElkReader.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class="rem"&gt;/// ElkReader opens a socket connection to the hardware panel. It then&lt;/span&gt;
&lt;span class="rem"&gt;/// enters a loop that&lt;/span&gt;
&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;public&lt;/span&gt; IEnumerator&amp;lt;ITask&amp;gt; ElkReader()
{
    Connect();

    &lt;span class="rem"&gt;// Send a request to the Elk panel get a report of the entire zone status.&lt;/span&gt;
    SendElkMessage(RequestStrings.ZoneStatus);

    &lt;span class="kwrd"&gt;byte&lt;/span&gt;[] buffer = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;[256];

    &lt;span class="kwrd"&gt;int&lt;/span&gt; bytesRead = -1;
    Exception ex = &lt;span class="kwrd"&gt;null&lt;/span&gt;;

     &lt;span class="kwrd"&gt;do&lt;/span&gt;
    {
        var ioResultPort = StreamAdapter.Read(networkStream, buffer, 0, buffer.Length);

        &lt;span class="kwrd"&gt;yield&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; (Choice)ioResultPort;

        ex = ioResultPort;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (ex != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            &lt;span class="kwrd"&gt;throw&lt;/span&gt; ex;

        bytesRead = ioResultPort;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (bytesRead != 0)
            ProcessRawElkMessage(Encoding.ASCII.GetString(buffer, 0, bytesRead));

    } &lt;span class="kwrd"&gt;while&lt;/span&gt; (bytesRead != 0);
}&lt;/pre&gt;
&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;When the ElkService receives a packet from the hardware panel, it converts the packet from a string to a custom message containing the raw sensor data and posts the message to the main port of the ElkService itself. For example, when the service receives a “ZC” message from the hardware, it converts this to an UpdateRawZone message that contains the raw data from the security panel. This happens in the method ProcessRawElkMessage. Here is a fragment of that code:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ProcessRawElkMessage(&lt;span class="kwrd"&gt;string&lt;/span&gt; message)
{
    &lt;span class="kwrd"&gt;string&lt;/span&gt; messageType = message.Substring(2, 2);

    &lt;span class="kwrd"&gt;switch&lt;/span&gt; (messageType)
    {
        &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;ZC&amp;quot;&lt;/span&gt;: &lt;span class="rem"&gt;// Zone status change&lt;/span&gt;
            var zoneState = &lt;span class="kwrd"&gt;new&lt;/span&gt; UpdateRawZoneRequest
            {
                Id = &lt;span class="kwrd"&gt;byte&lt;/span&gt;.Parse(message.Substring(4, 3)),
                State = &lt;span class="kwrd"&gt;byte&lt;/span&gt;.Parse(message.Substring(7, 1),
                              NumberStyles.HexNumber)
            };

            var updateZoneMessage = &lt;span class="kwrd"&gt;new&lt;/span&gt; UpdateRawZone();
            updateZoneMessage.Body = zoneState;

            _mainPort.Post(updateZoneMessage);
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
…&lt;/pre&gt;

&lt;p&gt;UpdateRawZoneRequest is the message payload and is used to send data about a zone change event to a subscriber. UpdateRawZone is the actual message type that is transmitted on the port for the ElkService.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;[DataContract]
[Description(&lt;span class="str"&gt;&amp;quot;UpdateRawZone Request Message Payload&amp;quot;&lt;/span&gt;)]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; UpdateRawZoneRequest
{
    [DataMember]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt; Id { get; set; }

    [DataMember]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt; State { get; set; }
}


&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class="rem"&gt;/// Update Elk zone status&lt;/span&gt;
&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
[Description(&lt;span class="str"&gt;&amp;quot;UpdateZone request message&amp;quot;&lt;/span&gt;)]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; UpdateRawZone : Update&amp;lt;UpdateRawZoneRequest,
        PortSet&amp;lt;DefaultUpdateResponseType, Fault&amp;gt;&amp;gt;
{
}&lt;/pre&gt;

&lt;p&gt;The message processing code can also be written a bit more compactly as:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ProcessRawElkMessage(&lt;span class="kwrd"&gt;string&lt;/span&gt; message)
{
    &lt;span class="kwrd"&gt;string&lt;/span&gt; messageType = message.Substring(2, 2);

    &lt;span class="kwrd"&gt;switch&lt;/span&gt; (messageType)
    {
        &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;&amp;quot;ZC&amp;quot;&lt;/span&gt;: &lt;span class="rem"&gt;// Zone status change&lt;/span&gt;
            var updateZoneMessage = &lt;span class="kwrd"&gt;new&lt;/span&gt; UpdateRawZone
            {
                Body = &lt;span class="kwrd"&gt;new&lt;/span&gt; UpdateRawZoneRequest
                {
                    Id = &lt;span class="kwrd"&gt;byte&lt;/span&gt;.Parse(message.Substring(4, 3)),
                    State = &lt;span class="kwrd"&gt;byte&lt;/span&gt;.Parse(message.Substring(7, 1),
                          NumberStyles.HexNumber)
                }
            };

            _mainPort.Post(updateZoneMessage);
            &lt;span class="kwrd"&gt;break&lt;/span&gt;;
…&lt;/pre&gt;

&lt;p&gt;UpdateRawZoneHandler is a message receiver that is active on the main port and which responds to the update message by updating internal state, and notifying subscribers of the change in state.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;[ServiceHandler(ServiceHandlerBehavior.Exclusive)]
&lt;span class="kwrd"&gt;public&lt;/span&gt; IEnumerator&amp;lt;ITask&amp;gt; UpdateRawZoneHandler(UpdateRawZone message)
{
    _state.ZoneStates[message.Body.Id - 1] = message.Body.State;

    SendNotification(_submgrPort, message);

    message.ResponsePort.Post(DefaultUpdateResponseType.Instance);

    &lt;span class="kwrd"&gt;yield&lt;/span&gt; &lt;span class="kwrd"&gt;break&lt;/span&gt;;
}&lt;/pre&gt;

&lt;h3&gt;In the Zone&lt;/h3&gt;

&lt;p&gt;The ElkService represents the core service that communicates with the Elk M1G hardware. The next service – ElkZoneSensor – represents a higher level “sensor array” that is attached to the Elk hardware. ElkZoneSensor “partners” with the ElkService. This means that the ElkZoneSensor relies on the ElkService to function. The DSS infrastructure will ensure that the ElkService is started if needed when starting the ElkZoneSensor service.&lt;/p&gt;

&lt;p&gt;The ElkZoneSensor subscribes to updates from the ElkService for changes in the hardware zones. When these changes occur, the ElkService notifies the ElkZoneSensor which updates its state and notifies any of its subscribers. The ElkZoneSensor uses a higher level message – UpdateZone – that contains a sensor ID and an enumeration that describes the state of the sensor.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;[DataContract]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Zone
{
    [DataMember]
    [Description(&lt;span class="str"&gt;&amp;quot;The Elk hardware zone id of the sensor&amp;quot;&lt;/span&gt;)]
    [DataMemberConstructor]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt; Id { get; set; }

    [DataMember]
    [Description(&lt;span class="str"&gt;&amp;quot;The Elk defined state of the sensor&amp;quot;&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; ZoneStatus Status { get; set; }
}&lt;/pre&gt;

&lt;h3&gt;Candlepower&lt;/h3&gt;

&lt;p&gt;The next services that we need for the robotic house are services to control the lights. In this case, I started with a &lt;i&gt;generic&lt;/i&gt; contract for the DSS service. A generic contract in DSS terms just defines the set of messages to which a service will respond and defines the port type on which those messages will be sent. The generic contract does not contain code to actually implement the service behavior. One of the benefits of a generic service contract is that you can specify the contract, write algorithms that use the contract, and later connect the generic service contracts to code that actually implements the behavior. This is very much like programming to an abstract interface in the object oriented world, and having multiple classes that actually implement the interface.&lt;/p&gt;

&lt;p&gt;We start off with a generic service called the GenericDimmer that represents a dimmer switch and we implement two concrete services: the SimulatedDimmer and the ZWaveDimmer. SimulatedDimmer just logs a message to represent its state change. The ZWaveDimmer actually controls the lights via a hardware Z-Wave controller.&lt;/p&gt;

&lt;p&gt;Here’s what the GenericDimmer contract looks like:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Robotics.GenericHouseControls.Dimmer
{


    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// GenericDimmer Contract class&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;sealed&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Contract
    {
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// The Dss Service contract&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        [DataMember]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; String Identifier = &lt;span class="str"&gt;&amp;quot;http://schemas.tempuri.org/2008/04/generichousecontrolsdimmer.html&amp;quot;&lt;/span&gt;;
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// The GenericDimmer State&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    [DataContract]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; GenericDimmerState
    {
        [DataMember]
        [DataMemberConstructor(Order = 1)]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Id;

        [DataMember]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Level;
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// GenericDimmer Main Operations Port&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    [ServicePort(AllowMultipleInstances = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; GenericDimmerOperations : PortSet&amp;lt;DsspDefaultLookup, DsspDefaultDrop, Get, HttpGet, On, Off, SetLevel&amp;gt;
    {
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// GenericDimmer Get Operation&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Get : Get&amp;lt;GetRequestType, PortSet&amp;lt;GenericDimmerState, Fault&amp;gt;&amp;gt;
    {

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// GenericDimmer Get Operation&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Get()
        {
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// GenericDimmer Get Operation&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Get(Microsoft.Dss.ServiceModel.Dssp.GetRequestType body) :
            &lt;span class="kwrd"&gt;base&lt;/span&gt;(body)
        {
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// GenericDimmer Get Operation&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Get(Microsoft.Dss.ServiceModel.Dssp.GetRequestType body, Microsoft.Ccr.Core.PortSet&amp;lt;GenericDimmerState, W3C.Soap.Fault&amp;gt; responsePort) :
            &lt;span class="kwrd"&gt;base&lt;/span&gt;(body, responsePort)
        {
        }
    }

    [DataContract]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; OnRequest
    {
    }

    [Description(&lt;span class="str"&gt;&amp;quot;Turn the switch on&amp;quot;&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; On : Update&amp;lt;OnRequest, PortSet&amp;lt;DefaultUpdateResponseType, Fault&amp;gt;&amp;gt;
    {
    }

    [DataContract]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; OffRequest
    {
    }

    [Description(&lt;span class="str"&gt;&amp;quot;Turn the switch off&amp;quot;&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Off : Update&amp;lt;OffRequest, PortSet&amp;lt;DefaultUpdateResponseType, Fault&amp;gt;&amp;gt;
    {
    }

    [DataContract]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SetLevelRequest
    {
        [DataMember]
        [DataMemberConstructor]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Level { get; set; }
    }

    [Description(&lt;span class="str"&gt;&amp;quot;Set the dim level&amp;quot;&lt;/span&gt;)]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SetLevel : Update&amp;lt;SetLevelRequest, PortSet&amp;lt;DefaultUpdateResponseType, Fault&amp;gt;&amp;gt;
    {
    }
}&lt;/pre&gt;

&lt;p&gt;This code defines the contract only. Now to implement that contract we can run the DssNewService utility with the /implement switch and generate a service based on this contract. For example: &lt;/p&gt;

&lt;p&gt;dssnewservice /s:SimulatedDimmer /n:Robotics.HouseControls.SimulatedDimmer /i:GenericHouseControls.Y2008.M04.Proxy.dll&lt;/p&gt;

&lt;p&gt;will generate a new service called SimulatedDimmer in the .NET namespace Robotics.HouseControls.SimulatedDimmer. The service will have a stubbed out implementation of the GenericDimmer contract including service startup code, state, and stubbed out message handlers.&lt;/p&gt;

&lt;p&gt;Here’s what the main service file looks like for the simulated dimmer after I added logging to the generated methods. I’ve also deleted some of the using statements for easier reading.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; pxdimmer = Robotics.GenericHouseControls.Dimmer.Proxy;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Robotics.HouseControls.SimulatedDimmer
{


    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// House Controls Service&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    [DisplayName(&lt;span class="str"&gt;&amp;quot;Simulated Dimmer&amp;quot;&lt;/span&gt;)]
    [Description(&lt;span class="str"&gt;&amp;quot;The Simulated Dimmer Switch Service&amp;quot;&lt;/span&gt;)]
    [Contract(Contract.Identifier)]
    [AlternateContract(pxdimmer.Contract.Identifier)]
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SimulatedDimmerService : DsspServiceBase
    {

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// _state&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        [ServiceState]
        [InitialStatePartner(Optional = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
        &lt;span class="kwrd"&gt;private&lt;/span&gt; pxdimmer.GenericDimmerState _state = &lt;span class="kwrd"&gt;new&lt;/span&gt; pxdimmer.GenericDimmerState();

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// _main Port&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        [ServicePort(&lt;span class="str"&gt;&amp;quot;/simulateddimmer&amp;quot;&lt;/span&gt;, AllowMultipleInstances = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]
        &lt;span class="kwrd"&gt;private&lt;/span&gt; pxdimmer.GenericDimmerOperations _mainPort = &lt;span class="kwrd"&gt;new&lt;/span&gt; pxdimmer.GenericDimmerOperations();


        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Default Service Constructor&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; SimulatedDimmerService(DsspServiceCreationPort creationPort) :
            &lt;span class="kwrd"&gt;base&lt;/span&gt;(creationPort)
        {
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Service Start&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Start()
        {
            &lt;span class="kwrd"&gt;base&lt;/span&gt;.Start();

            &lt;span class="rem"&gt;// Add service specific initialization here.&lt;/span&gt;
            LogInfo(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;&amp;quot;Dimmer State =&amp;gt; Id:{0} Level:{1}&amp;quot;&lt;/span&gt;, _state.Id, _state.Level));
        }

        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; IEnumerator&amp;lt;ITask&amp;gt; OnHandler(pxdimmer.On update)
        {
            LogInfo(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;&amp;quot;Simulated Dimmer =&amp;gt; Id:{0} On&amp;quot;&lt;/span&gt;, _state.Id));

            update.ResponsePort.Post(DefaultUpdateResponseType.Instance);
            &lt;span class="kwrd"&gt;yield&lt;/span&gt; &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        }

        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; IEnumerator&amp;lt;ITask&amp;gt; OffHandler(pxdimmer.Off update)
        {
            LogInfo(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;&amp;quot;Simulated Dimmer =&amp;gt; Id:{0} Off&amp;quot;&lt;/span&gt;, _state.Id));

            update.ResponsePort.Post(DefaultUpdateResponseType.Instance);
            &lt;span class="kwrd"&gt;yield&lt;/span&gt; &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        }

        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; IEnumerator&amp;lt;ITask&amp;gt; SetLevelHandler(pxdimmer.SetLevel update)
        {           
            _state.Level = update.Body.Level;
            LogInfo(&lt;span class="kwrd"&gt;string&lt;/span&gt;.Format(&lt;span class="str"&gt;&amp;quot;Simulated Dimmer =&amp;gt; Id:{0} Level:{1}&amp;quot;&lt;/span&gt;, _state.Id, update.Body.Level));

            update.ResponsePort.Post(DefaultUpdateResponseType.Instance);            
            &lt;span class="kwrd"&gt;yield&lt;/span&gt; &lt;span class="kwrd"&gt;break&lt;/span&gt;;
        }
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;



.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;Check the code download for the implementation of the ZWaveDimmer. You’ll find that it’s pretty straightforward. It should be simple to write similar code if you use a different technology for lighting control. You just write a service that matches the GenericDimmer contract, and you should be able to configure the GenericDimmer using a manifest to point to the actual dimmer service. Check out the documentation in Microsoft Robotics Developer Studio for more information on manifests and how to use the manifest editor.&lt;/p&gt;

&lt;h3&gt;Bulb On, Bulb Off!&lt;/h3&gt;

&lt;p&gt;The “Hello, World” application for any home automation software that I’ve tested in my house has always been the automating of my pantry light. The pantry has a Z-Wave light switch inside and the pantry door has a contact switch that is connected to the Elk M1G. When the door is open, we want the light to turn on, and when the door is closed we want the light to turn off. Now that we have all the pieces for this, here’s what the VPL diagram for this looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/HomeAutomationwithMicrosoftRoboticsDevel_13D2/image.png"&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="259" alt="image" src="http://www.coding4fun.net/images/HomeAutomationwithMicrosoftRoboticsDevel_13D2/image_thumb.png" width="500" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;As you can see, it was also a relatively easy matter to add text-to-speech to announce the opening and closing of the pantry door. You may find out quickly that this is an annoyance to those in the testing areas – for me that was my kitchen – so it’s nice to know that two quick hits of the delete key will also remove the text-to-speech. This is part of the beauty of the Microsoft Robotics programming model!&lt;/p&gt;

&lt;p&gt;The second example shows how you can use a motion detector – in this case connected to zone 19 on the Elk – to trigger a light. The light comes on at a level that you control from the VPL code, and stays on for a duration that you can also control from the code. For the example, I set the timer to a pretty low level, but you can customize it. You could also add additional rules to only turn on the light at certain times, or better still connect an ambient light sensor to decide whether you should turn the light on.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.coding4fun.net/images/HomeAutomationwithMicrosoftRoboticsDevel_13D2/image_3.png"&gt;&lt;img title="image" style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="319" alt="image" src="http://www.coding4fun.net/images/HomeAutomationwithMicrosoftRoboticsDevel_13D2/image_thumb_3.png" width="500" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In this diagram, if motion is detected – that is zone 19 is triggered with a status of ViolatedOpen – the light is turned on at a low dim level and a timer is set. When the timer completes, the light is turned off. If, however, there is more motion before the timer completes, the SetTimer message will cancel the old timeout and restart the timer.&lt;/p&gt;

&lt;p&gt;There are more VPL examples included in the download including an extra service that you can use to send email from your VPL code. I’m experimenting with using the email service to send me a text message whenever my alarm is armed or disarmed.&lt;/p&gt;

&lt;h3&gt;Miscellanea&lt;/h3&gt;

&lt;p&gt;Since I haven’t had a lot of time to study the testing framework and simulation environments used by Microsoft Robotics, I included a service called the ElkTestDataPlayback service that allows me to replay the contents of a text file to simulate the ElkService getting actual data. This works pretty well for testing. The contents of the file are merely raw data captures that I made from the data sent by the Elk M1G panel. To use this service in VPL, you just drop it onto your diagram, configure it’s TestDataFileName via “Set initial configuration” to point to a data file, and send it a message to start playback.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&lt;font color="#ff0000"&gt;Important&lt;/font&gt;:&lt;/b&gt; If you have the Elk hardware, you will want to uncomment the &lt;i&gt;SpawnIterator(ElkReader)&lt;/i&gt; line in the ElkService.Start method. I know this is a hack for now. It would probably be better to write a SimulatedElk service based on a generic service contract. If I have time, I will do that in the future. That would involve a lot more work than I had for this weekend project!&lt;/p&gt;

&lt;h3&gt;TODO List&lt;/h3&gt;

&lt;p&gt;Since this was my first foray into Microsoft Robotics Developer Studio and I had limited time to really explore the features in depth, there are a few things that I’ve left unimplemented. Here are some of the things that I would like to expand on in the future:&lt;/p&gt;

&lt;p&gt;1. &lt;b&gt;Support for more of the Elk features:&lt;/b&gt; Currently, I only support Zone Change notifications. Fuller support of the Elk hardware would not be difficult and would be beneficial to anyone wanting to use this on an ongoing basis. There’s some stub code for a few other notifications if you want to add to the service.&lt;/p&gt;

&lt;p&gt;2. &lt;b&gt;Generic contracts for the Elk M1G:&lt;/b&gt; I didn’t base the Elk services on generic contract because I’m not familiar with enough other types of security and automation panels to make the needed generalizations. It would be interesting to try to come up with something more generic. I thought about using the Generic Contact Sensor array, but I’m not sure that it models what we need. For example, a door contact is considered &lt;b&gt;&lt;i&gt;violated&lt;/i&gt;&lt;/b&gt; when it’s open, but a water sensor is considered &lt;b&gt;&lt;i&gt;violated&lt;/i&gt;&lt;/b&gt; when it’s closed.&lt;/p&gt;

&lt;p&gt;3. &lt;b&gt;Additional Z-Wave features:&lt;/b&gt; I’ve left out notification for lighting level changes, support for scenes and a host of other features. There’s so much more that’s possible with full Z-Wave support.&lt;/p&gt;

&lt;p&gt;4. &lt;b&gt;Refined Generic Contracts:&lt;/b&gt; Generic contracts allow developers to write code that is independent of the final hardware. That is one of the major benefits of the model used by Microsoft Robotics. You could for example have a generic light switch for simulation and testing, and based on configuration you could plug in a Z-Wave switch or an Insteon switch when it’s time to deploy the actual solution.&lt;/p&gt;

&lt;p&gt;5. &lt;b&gt;Simulation Support:&lt;/b&gt; One of the major benefits of Microsoft Robotics Developer Studio is the simulation environment. For example, if we had a motion detector in the simulation environment, we could test some of the algorithms that I presented above by having a simulated mobile robot “violate” the motion detector’s zone and trigger the corresponding VPL code.&lt;/p&gt;

&lt;p&gt;6. &lt;b&gt;Exception Handling:&lt;/b&gt; As I build more on the code in this article, I’ll add exception handling and retry logic. Microsoft Robotics has some extremely robust features such as Causalities that make handling exceptions in a concurrent environment much easier.&lt;/p&gt;

&lt;p&gt;7. &lt;b&gt;HttpHandlers:&lt;/b&gt; I have a start at code for handling HTTP requests in the ZWaveController service. Handling HTTP requests is handy for building client applications that access your services without themselves having to be DSS services.&lt;/p&gt;

&lt;p&gt;Other experiments that might be fun to try include integrating your Microsoft Robotics controlled home with remote control applications that are based on WPF or Silverlight, or perhaps integrating control from a Windows Media Center PC or Windows Home Server.&lt;/p&gt;

&lt;p&gt;I hope you enjoy Microsoft Robotics Developer Studio as much as I have. I look forward to seeing what other people build with this fantastic technology. If people are interested, I can continue to share my home automation experiments. I think Microsoft Robotics Developer Studio will be the major tool in my home automation toolbox for quite some time.&lt;/p&gt;

&lt;h3&gt;Project Settings Note:&lt;/h3&gt;

&lt;p&gt;You will have to modify the project settings for the projects included in the House.Robot solution since your installation of Microsoft Robotics Developer Studio will be in a different directory than mine. The DssProjectMigration.exe command line tool will make short work of this. Just run it with a parameter that specifies the directory you want it to search, and it will find all of the project files in that directory and subdirectories and convert them to be buildable with your installation settings.&lt;/p&gt;

&lt;p&gt;If you use the ElkTestDataPlayback service, in the examples, you’ll need to set the path to the location of the test data file either in the initial configuration for the component, or in a manifest that configures the component. Make sure that you &lt;b&gt;do not&lt;/b&gt; put quotes around the path name. I included a test data file from my system.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8544962" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/home+automation/default.aspx">home automation</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/robotics/default.aspx">robotics</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/hardware/default.aspx">hardware</category></item><item><title>Control Windows Media Center using a Windows Mobile 5 Device</title><link>http://blogs.msdn.com/coding4fun/archive/2007/05/14/2632164.aspx</link><pubDate>Mon, 14 May 2007 20:08:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:2632164</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>52</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/2632164.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=2632164</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=2632164</wfw:comment><description>&lt;P&gt;This article demonstrates how to use a smartphone running Windows Mobile 5 to remotely control a host machine running Windows Media Center. I will describe how to create an add-in application that runs within Windows Media Center, and how to create a Windows Mobile 5 application that you can use to communicate with the Media Center over a wireless internet connection. Finally, I will demonstrate how to use this implementation to manipulate Media Center using the Windows Media Center API. &lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.claritycon.com/blogs/matt_ivers/default.aspx" mce_href="http://blogs.claritycon.com/blogs/matt_ivers/default.aspx"&gt;Matt Ivers&lt;/A&gt; 
&lt;P&gt;&lt;B&gt;Difficulty: &lt;/B&gt;Intermediate 
&lt;P&gt;&lt;B&gt;Time Required:&lt;/B&gt; 6-10 hours&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Cost: &lt;/B&gt;$100-$200 &lt;/P&gt;
&lt;P&gt;&lt;B&gt;Software: &lt;/B&gt;&lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyID=dc6c00cb-738A-4B97-8910-5cd29ab5f8d9&amp;amp;DisplayLang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=dc6c00cb-738A-4B97-8910-5cd29ab5f8d9&amp;amp;DisplayLang=en"&gt;Visual Basic or Visual C# Express Editions&lt;/A&gt;, &lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyId=A43EA0B7-B85F-4612-AA08-3BF128C5873E&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyId=A43EA0B7-B85F-4612-AA08-3BF128C5873E&amp;amp;displaylang=en"&gt;Windows Media Center SDK 5.0&lt;/A&gt;, &lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyID=dc6c00cb-738A-4B97-8910-5cd29ab5f8d9&amp;amp;DisplayLang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=dc6c00cb-738A-4B97-8910-5cd29ab5f8d9&amp;amp;DisplayLang=en"&gt;Windows Mobile 5.0 Smartphone SDK&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&lt;B&gt;Hardware: &lt;/B&gt;Mobile device running Windows Mobile 5.0 &lt;/P&gt;
&lt;P&gt;&lt;B&gt;Download: &lt;/B&gt;&lt;A href="http://www.coding4fun.net/source/WMC_Remote_Code.zip" mce_href="http://www.coding4fun.net/source/WMC_Remote_Code.zip"&gt;C# and VB.Net&lt;/A&gt;&lt;/P&gt;
&lt;UL&gt;&lt;/UL&gt;
&lt;H3&gt;Introduction&lt;/H3&gt;Starting with Windows Media Center Edition 2005, Media Center added extensibility support through hosted add-in assemblies. By implementing an add-in interface and registering the assembly with Media Center, the add-in assembly is given access to the Microsoft.MediaCenter.Hosting.AddInHost object. Using this object model, an add-in assembly can programmatically inspect and manipulate various aspects of Windows Media Center. In addition to the exposed Media Center namespaces, the add-in has complete access to all the capabilities of the .NET Framework. 
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;By combining the power of a Media Center add-in with a mobile device running Windows Mobile 5.0, we can extend the capabilities of a Media Center add-in even further. The add-in service I developed runs as a listener service within Windows Media Center on the host machine. It is initialized when Windows Media Center is started, runs invisibly in the background, and allows mobile devices to connect and submit requests to it. The mobile solution leverages an existing WiFi internet connection to communicate with the add-in via TCP socket connections. The mobile device runs a .NET Compact Framework 2.0 forms application designed for devices running Windows Mobile 5 or higher.&lt;/P&gt;
&lt;P&gt;The included remote control application is capable of the following functionality: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Retrieve metadata about currently loaded media 
&lt;LI&gt;Affect playback of currently loaded media – Play, Pause, Stop, Next Track, Previous Track 
&lt;LI&gt;Control Media Center volume 
&lt;LI&gt;Retrieve a list of available media – Photos, Audio, Video 
&lt;LI&gt;Explicitly load media for playback – Audio, Video &lt;/LI&gt;&lt;/UL&gt;
&lt;H3&gt;Creating a Windows Media Center add-in application&lt;/H3&gt;The first step in our implementation is creating an add-in that will run within Windows Media Center. This involves creating a new Windows Media Center Presentation Layer Application project, implementing an interface, signing the assembly, and creating a setup project to install the assembly and register it with Media center. 
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H4&gt;Creating a new project – Windows Media Center Presentation Layer Application&lt;/H4&gt;Installing the Windows Media Center SDK makes this step simple. Once installed, you create this project like any other in Visual Studio: 
&lt;P&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" border=0 src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/1_Create_new_WMC_presentation_layer_.jpg" width=500 height=351 mce_src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/1_Create_new_WMC_presentation_layer_.jpg"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Figure 1 - Creating the project&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;Using the Windows Media Center Presentation Layer Application project template yields the following project skeleton:&lt;/P&gt;
&lt;P&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" border=0 src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/2_AddIn_demo_project3.jpg" width=209 height=240 mce_src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/2_AddIn_demo_project3.jpg"&gt; &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Figure&amp;nbsp;2 - Solution Explorer for our new project&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;There are two files of interest here: AddIn.vb and App.xml. AddIn.vb contains our add-in class. Interface methods implemented in this class will be invoked by Windows Media Center when our add-in is launched. App.xml contains configuration information identifying our assemblies and add-in attributes. The setup project will use this XML to register our add-in with Windows Media Center during installation. &lt;/P&gt;
&lt;H4&gt;The AddIn class&lt;/H4&gt;Media Center add-in applications must implement two interfaces in order for Media Center to invoke them: Microsoft.MediaCenter.Hosting.IAddInEntryPoint, and Microsoft.MediaCenter.Hosting.IAddInModule. By using the project template, our add-in class already implements both (AddIn.vb): 
&lt;H5&gt;&lt;SPAN class=kwrd&gt;&lt;STRONG&gt;Visual Basic&lt;/STRONG&gt;&lt;/SPAN&gt; .NET&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Class&lt;/SPAN&gt; Class1
    &lt;SPAN class=kwrd&gt;Implements&lt;/SPAN&gt; IAddInModule
    &lt;SPAN class=kwrd&gt;Implements&lt;/SPAN&gt; IAddInEntryPoint

    &lt;SPAN class=rem&gt;' Initialize (IAddInModule)&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; Initialize(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; appInfo &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Dictionary(Of &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;Object&lt;/SPAN&gt;), &lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; entryPointInfo &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Dictionary(Of &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;Object&lt;/SPAN&gt;)) &lt;SPAN class=kwrd&gt;Implements&lt;/SPAN&gt; IAddInModule.Initialize
        &lt;SPAN class=rem&gt;' Initialization logic goes here&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt;

    &lt;SPAN class=rem&gt;' Uninitialize (IAddInModule)&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; Uninitialize() &lt;SPAN class=kwrd&gt;Implements&lt;/SPAN&gt; IAddInModule.Uninitialize
        &lt;SPAN class=rem&gt;' Clean-up logic goes here&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt;

    &lt;SPAN class=rem&gt;' Launch (IAddInEntryPoint)&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; Launch(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; host &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; AddInHost) &lt;SPAN class=kwrd&gt;Implements&lt;/SPAN&gt; IAddInEntryPoint.Launch
        &lt;SPAN class=rem&gt;' This is where normal execution begins&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; Class&lt;/PRE&gt;
&lt;H5&gt;Visual C#&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; Class1 : IAddInModule, IAddInEntryPoint 
{
    &lt;SPAN class=rem&gt;//  Initialize (IAddInModule)&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Initialize(Dictionary&amp;lt;&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt;&amp;gt; appInfo, Dictionary&amp;lt;&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt;&amp;gt; entryPointInfo)
    {
        &lt;SPAN class=rem&gt;//  Initialization logic goes here&lt;/SPAN&gt;
    }    
    &lt;SPAN class=rem&gt;//  Uninitialize (IAddInModule)&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Uninitialize() 
    {
        &lt;SPAN class=rem&gt;//  Clean-up logic goes here&lt;/SPAN&gt;
    }    
    &lt;SPAN class=rem&gt;//  Launch (IAddInEntryPoint)&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Launch(AddInHost host) 
    {
        &lt;SPAN class=rem&gt;//  This is where normal execution begins&lt;/SPAN&gt;
    }
}
&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100%
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;The IAddInModule.Initialize and IAddInModule.Uninitialize interface methods are used by Media Center to signal the beginning and end of the add-in application’s lifetime. Use Initialize to create any internal objects your application may require, and the Uninitialize to perform any clean-up. Keep in mind that since the add-in application runs within Media Center, it may decide to close your add-in application before it has a chance to exit on its own. In any case, Media Center will call the Uninitialize method and give the add-in a window of execution to exit as gracefully as possible. &lt;/P&gt;
&lt;P&gt;The IAddInEntryPoint.Launch method is where normal execution code should begin. Media Center will pass an AddInHost object as an input parameter. Through this object, your add-in application can access all the features of the Media Center API. 
&lt;H4&gt;Signing the assembly&lt;/H4&gt;Windows Media Center requires that all add-in assemblies be strongly-named. This requires that the assembly be signed using a key file. Thanks to Visual Studio 2005, signing an assembly is a straightforward process. From your add-in project’s “Properties” menu, you can browse to the “Signing” tab to create a new strong name key file for the project: 
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/3_Sign_an_assembly4.jpg" atomicselection="true" mce_href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/3_Sign_an_assembly4.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" border=0 src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/3_Sign_an_assembly_thumb2.jpg" width=500 height=327 mce_src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/3_Sign_an_assembly_thumb2.jpg"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Figure 3 -&amp;nbsp;Signing our assembly&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;Explicit instruction is also available here:&lt;BR&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/ms247123(VS.80).aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms247123(VS.80).aspx"&gt;How to: Sign an Assembly (Visual Studio)&lt;/A&gt;&lt;/P&gt;
&lt;H4&gt;Tweaking the App.xml file&lt;/H4&gt;Media Center requires every add-in application to explicitly define a point of entry by which the application is to be launched. The App.xml file contains this configuration information. The Media Center project template used earlier generates the following sample: 
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;application&lt;/SPAN&gt; &lt;SPAN class=attr&gt;title&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="DemoProject"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;id&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="{f6dd1141-f288-46fe-bcdb-2d9c5ffd986e}"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;entrypoint&lt;/SPAN&gt; &lt;SPAN class=attr&gt;id&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="{31a15ce9-0487-43bc-94de-a43409129641}"&lt;/SPAN&gt; 
              &lt;SPAN class=attr&gt;addin&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="DemoProject.Class1, DemoProject,Culture=Neutral,Version=6.0.6000.0"&lt;/SPAN&gt;
              &lt;SPAN class=attr&gt;title&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="DemoProject"&lt;/SPAN&gt;
              &lt;SPAN class=attr&gt;description&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="DemoProject"&lt;/SPAN&gt;
              &lt;SPAN class=attr&gt;ImageUrl&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;=".\AppIcon.png"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;category&lt;/SPAN&gt; &lt;SPAN class=attr&gt;category&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="More Programs"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;/&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;entrypoint&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;application&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;/PRE&gt;
&lt;P&gt;The XML definition specifies the add-in applications and their points of entry within Media Center. Add-in applications can be launched on demand from various locations within Media Center, such as from an icon in the “More Programs” group. A full listing of all the available points of entry can be found here. Add-in applications can also be launched in the background when Media Center starts. To indicate this, we specify “Background” in the “category” attribute. The “addin” attribute must also be modified to point to our add-in class in the format “Assemblyname.ClassName”. The “title”, “description”, and “ImageUrl” attributes are used primarily for on-demand add-ins. 
&lt;P&gt;After making our changes, the Windows Media Center Remote application XML looks like this:&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;application&lt;/SPAN&gt; &lt;SPAN class=attr&gt;title&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="WMCServerAddIn"&lt;/SPAN&gt; &lt;SPAN class=attr&gt;id&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="{7b71a7ca-b459-4023-ab12-d5cc8c56b991}"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;entrypoint&lt;/SPAN&gt; &lt;SPAN class=attr&gt;id&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="{5fe9982b-ca4a-459e-b62c-40399e875d66}"&lt;/SPAN&gt; 
              &lt;SPAN class=attr&gt;addin&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="WMCServerAddIn.ServerAddIn, WMCServerAddIn,Culture=Neutral,Version=6.0.6000.0"&lt;/SPAN&gt;
              &lt;SPAN class=attr&gt;title&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="WMCServerAddIn"&lt;/SPAN&gt;
              &lt;SPAN class=attr&gt;description&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="WMCServerAddIn"&lt;/SPAN&gt;
              &lt;SPAN class=attr&gt;ImageUrl&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;=".\AppIcon.png"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class=html&gt;category&lt;/SPAN&gt; &lt;SPAN class=attr&gt;category&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;="Background"&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;/&amp;gt;&lt;/SPAN&gt;
  &lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;entrypoint&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN class=html&gt;application&lt;/SPAN&gt;&lt;SPAN class=kwrd&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;H4&gt;Creating the setup project&lt;/H4&gt;
&lt;P&gt;With a basic interface implementation complete and a configuration XML created, we are ready to create the setup project. The setup project will install our assemblies into the Global Assembly Cache and register our XML-defined entry point with Media Center. A full step-by-step walkthrough can be found here:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/MedctrSDK/htm/creatingawindowsinstallerfileforanaddin.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/MedctrSDK/htm/creatingawindowsinstallerfileforanaddin.asp"&gt;Creating a Windows Installer File for a Windows Media Center Add-in&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Once the setup project is complete, it’s time for a test. By using the Host.MediaCenterEnvironment.Dialog class off of the AddInHost object, we can present a dialog box to the user to ensure the add-in launches successfully. After compiling the solution, run the installer by right-clicking the setup project and choosing “Install”. Once installation has completed, run Windows Media Center. A few seconds after startup, the add-in is launched:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/4_Hello_world_demo_addin3.jpg" atomicselection="true" mce_href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/4_Hello_world_demo_addin3.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" border=0 src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/4_Hello_world_demo_addin_thumb1.jpg" width=500 height=374 mce_src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/4_Hello_world_demo_addin_thumb1.jpg"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Figure 4 - Running our Hello World Media Center Add-in&lt;/EM&gt;&lt;/P&gt;
&lt;H3&gt;Creating a Windows Mobile 5.0 client application&lt;/H3&gt;The second step in our implementation is creating a .NET Compact Framework 2.0 forms application. This is a mobile application that will run on a mobile device running Windows Mobile 5 or higher. 
&lt;H4&gt;Creating a new project – Windows Mobile CE 5.0 application&lt;/H4&gt;
&lt;P&gt;Installing the Windows Mobile Smartphone SDK 5.0 makes this step simple. Once the SDK is installed, you can create a project in Visual Studio using the Windows CE 5.0 Project template. &lt;/P&gt;
&lt;P&gt;The only other typical setup required for developing mobile apps is to change the deployment settings to point to your WM5 device. This can be configured within the Visual Studio toolbar: &lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/6_Deploying_to_mobile3.jpg" atomicselection="true" mce_href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/6_Deploying_to_mobile3.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" border=0 src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/6_Deploying_to_mobile_thumb1.jpg" width=345 height=201 mce_src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/6_Deploying_to_mobile_thumb1.jpg"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Figure&amp;nbsp;5 - changing the deployment settings to target the mobile device&lt;/EM&gt;&lt;/P&gt;
&lt;H3&gt;Implementing the Media Center Add-in service&lt;/H3&gt;With a test harness in place at both ends of the implementation, it was time to get to the real code. To facilitate the control of Media Center through the hosted add-in, the service requires a few key components. These include choosing a server / client conversation protocol, creating a multithreaded socket server, implementing object serialization, and implementing the programmatic manipulation of Media Center. 
&lt;H4&gt;Implementing the socket server&lt;/H4&gt;
&lt;P&gt;The socket server uses the Socket object from the System.Networking.Sockets namespace for all of its communications. The listener service begins by binding to the host machine’s local address and listening on a port of your choosing. Once the socket is instantiated and bound to a local port, it begins listening for and accepting inbound connections. When a new connection is established, a target method BeginSocketConversation will be invoked on a new thread, where the actual communication between the two parties will take place. Once the new thread has been invoked, execution will continue in the AcceptConnections method. At this time the newly launched thread notifies the listener to begin accepting new connections again. A ManualResetEvent from the System.Threading namespace can be used to communicate changes in state between two or more threads. Here is the code implementation of the socket listener: &lt;/P&gt;
&lt;H5&gt;&lt;SPAN class=kwrd&gt;Visual Basic .NET&lt;/SPAN&gt;&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; AcceptConnections()
        &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; localMachineInfo &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; IPHostEntry
        &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; localEndPoint &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; IPEndPoint
        &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; listener &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
        &lt;SPAN class=kwrd&gt;Try&lt;/SPAN&gt;
            localMachineInfo = Dns.Resolve(&lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;.Empty)
            localEndPoint = &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; IPEndPoint(localMachineInfo.AddressList(0), _port)
            listener.Bind(localEndPoint)
            listener.Listen(10)
            &lt;SPAN class=kwrd&gt;While&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;
                threadEvent.Reset()
                listener.BeginAccept(&lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; AsyncCallback(&lt;SPAN class=kwrd&gt;AddressOf&lt;/SPAN&gt; BeginSocketConversation), listener)
                threadEvent.WaitOne()
            &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;While&lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;Catch&lt;/SPAN&gt; ex &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Exception
          Log.Write(ex)
    &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Try&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt;
&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100%
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;H5&gt;Visual C#&lt;/H5&gt;&lt;PRE class=csharpcode&gt;Public Class Class1
    Implements IAddInModule
    Implements IAddInEntryPoint

    &lt;SPAN class=str&gt;' Initialize (IAddInModule)
    Public Sub Initialize(ByVal appInfo As Dictionary(Of String, Object), ByVal entryPointInfo As Dictionary(Of String, Object)) Implements IAddInModule.Initialize
        '&lt;/SPAN&gt; Initialization logic goes here
    End Sub

    &lt;SPAN class=str&gt;' Uninitialize (IAddInModule)
    Public Sub Uninitialize() Implements IAddInModule.Uninitialize
        '&lt;/SPAN&gt; Clean-up logic goes here
    End Sub

    &lt;SPAN class=str&gt;' Launch (IAddInEntryPoint)
    Public Sub Launch(ByVal host As AddInHost) Implements IAddInEntryPoint.Launch
        '&lt;/SPAN&gt; This &lt;SPAN class=kwrd&gt;is&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;where&lt;/SPAN&gt; normal execution begins
    End Sub
End Class&lt;/PRE&gt;
&lt;P&gt;Once a connection has been established, the server begins to listen for inbound messages. When new data is received, it is parsed into a custom Message object for easy inspection by a consuming class. An event is then raised to any consuming classes, passing a reference to the newly created Message object. The server then resumes listening for new data on the same socket. Here is the code implementation:&lt;/P&gt;
&lt;H5&gt;Visual Basic .NET&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; BeginSocketConversation(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; ar &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; IAsyncResult)
    threadEvent.&lt;SPAN class=kwrd&gt;Set&lt;/SPAN&gt;()
    &lt;SPAN class=kwrd&gt;RaiseEvent&lt;/SPAN&gt; ClientConnected()
    &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; listener &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Socket = &lt;SPAN class=kwrd&gt;CType&lt;/SPAN&gt;(ar.AsyncState, Socket)
    _socket = listener.EndAccept(ar)
    &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; buffer(PACKET_SIZE) &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Byte&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; bytesReadCount &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Integer&lt;/SPAN&gt; = 0
    &lt;SPAN class=kwrd&gt;While&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;True&lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; sb &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; System.Text.StringBuilder
        &lt;SPAN class=kwrd&gt;Do&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;Try&lt;/SPAN&gt;
                bytesReadCount = _socket.Receive(buffer, buffer.Length, SocketFlags.None)
            &lt;SPAN class=kwrd&gt;Catch&lt;/SPAN&gt; ex &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Exception
                _socket.Close()
                &lt;SPAN class=kwrd&gt;Exit&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;While&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Try&lt;/SPAN&gt;
            sb.Append(System.Text.ASCIIEncoding.ASCII.GetString(buffer, 0, bytesReadCount))
        &lt;SPAN class=kwrd&gt;Loop&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;While&lt;/SPAN&gt; _socket.Available &amp;gt; 0
        &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; requestMessage &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; RequestMessage()
        requestMessage.DeSerialize(sb.ToString())
        &lt;SPAN class=kwrd&gt;RaiseEvent&lt;/SPAN&gt; MessageReceived(requestMessage)
    &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;While&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;RaiseEvent&lt;/SPAN&gt; ClientDisconnected()
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;H5&gt;&lt;SPAN class=kwrd&gt;Visual C#&lt;/SPAN&gt;&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; BeginSocketConversation(IAsyncResult ar)
{
    threadEvent.Set();
    ClientConnected();
    Socket listener = ((Socket)(ar.AsyncState));
    _socket = listener.EndAccept(ar);
    &lt;SPAN class=kwrd&gt;byte&lt;/SPAN&gt;[,] buffer;
    &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; bytesReadCount = 0;
    &lt;SPAN class=kwrd&gt;while&lt;/SPAN&gt; (&lt;SPAN class=kwrd&gt;true&lt;/SPAN&gt;)
    {
        System.Text.StringBuilder sb = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; System.Text.StringBuilder();
        &lt;SPAN class=kwrd&gt;for&lt;/SPAN&gt; (
        ; (_socket.Available &amp;gt; 0);
        )
        {
            &lt;SPAN class=kwrd&gt;try&lt;/SPAN&gt;
            {
                bytesReadCount = _socket.Receive(buffer, buffer.Length, SocketFlags.None);
            }
            &lt;SPAN class=kwrd&gt;catch&lt;/SPAN&gt; (Exception ex)
            {
                _socket.Close();
                &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;
            }
            sb.Append(System.Text.ASCIIEncoding.ASCII.GetString(buffer, 0, bytesReadCount));
        }
        RequestMessage requestMessage = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; RequestMessage();
        requestMessage.DeSerialize(sb.ToString());
        MessageReceived(requestMessage);
    }
    ClientDisconnected();
}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100%
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;H4&gt;Object serialization&lt;/H4&gt;The limited resources of a mobile device require an efficient method of transferring data and commands between the device and the host machine. Due to their large size, the .NET remoting libraries and the binary serialization libraries provided by .NET 2.0 are not available in the .NET Mobile Framework. I chose custom serialization to facilitate the transfer of objects. While less flexible, this enabled objects to be transferred using very little bandwidth. 
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H4&gt;Implementing the AddIn.Launch method&lt;/H4&gt;
&lt;P&gt;The custom server object created in the previous section encapsulates all the grunt work of socket-level protocol, accepting connections, serializing / deserializing message objects, and data transfer. Within the AddIn class implementation, all we have to do now is instantiate the Server class, indicating the port to listen on: &lt;/P&gt;
&lt;H5&gt;Visual Basic .NET&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; Launch(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; host &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; AddInHost) &lt;SPAN class=kwrd&gt;Implements&lt;/SPAN&gt; IAddInEntryPoint.Launch
    _wmcHost = host
    _waitForExit = &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; System.Threading.ManualResetEvent(&lt;SPAN class=kwrd&gt;False&lt;/SPAN&gt;)
    _server.Start(DEFAULT_PORT)
    System.Threading.Thread.CurrentThread.Priority = Threading.ThreadPriority.Lowest
    _waitForExit.WaitOne()
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; Sub&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100%
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;H5&gt;Visual C#&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; Launch(AddInHost host) 
{
    _wmcHost = host;
    _waitForExit = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; System.Threading.ManualResetEvent(&lt;SPAN class=kwrd&gt;false&lt;/SPAN&gt;);
    _server.Start(DEFAULT_PORT);
    System.Threading.Thread.CurrentThread.Priority = Threading.ThreadPriority.Lowest;
    _waitForExit.WaitOne();
}&lt;/PRE&gt;
&lt;P&gt;We also perform two other critical tasks at this time. First, we assign a reference to the AddInHost to a private member variable for later use. Second, we reduce the priority of the add-in’s main thread and use a ManualResetEvent to put it to sleep until Media Center is closed. The reason for this relates to the nature of an add-in’s lifetime within Media Center. The Media Center add-in hosting process will only allow an add-in to execute for the duration of its Launch method. This means that as soon as the Launch method returns, the add-in and any child threads it has spawned will be terminated. For this reason, we must keep the add-in alive by blocking the Launch method from exiting. 
&lt;H4&gt;Media Center manipulation&lt;/H4&gt;
&lt;P&gt;Using the communications layer and socket listener developed in the previous sections, we can finally get to the task of performing something useful with the input requests. By subscribing to the custom Server object’s MessageReceived event, the AddIn class’s OnDataReceived method will automatically be invoked when a new request message is received from the listener: &lt;/P&gt;
&lt;H5&gt;Visual Basic .NET&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; OnDataReceived(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; message &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; RequestMessage) &lt;SPAN class=kwrd&gt;Handles&lt;/SPAN&gt; _server.MessageReceived
    &lt;SPAN class=kwrd&gt;Select&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Case&lt;/SPAN&gt; message.RequestAction
        &lt;SPAN class=kwrd&gt;Case&lt;/SPAN&gt; RequestMessage.Action.PauseMedia
_wmcHost.MediaCenterEnvironment.MediaExperience.Transport.PlayRate = PlayRates.PLAYRATE_PAUSE
        &lt;SPAN class=kwrd&gt;Case&lt;/SPAN&gt; RequestMessage.Action.VolumeUp
           _wmcHost.MediaCenterEnvironment.AudioMixer.VolumeUp()
        &lt;SPAN class=kwrd&gt;Case&lt;/SPAN&gt; RequestMessage.Action.VolumeDown
           _wmcHost.MediaCenterEnvironment.AudioMixer.VolumeDown()
        &lt;SPAN class=kwrd&gt;Case&lt;/SPAN&gt; RequestMessage.Action.NextMedia _wmcHost.MediaCenterEnvironment.MediaExperience.Transport.SkipForward()
        &lt;SPAN class=kwrd&gt;Case&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Else&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Select&lt;/SPAN&gt;
    SendAcknowledgement(message)
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt;&lt;/PRE&gt;
&lt;H5&gt;Visual C#&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; OnDataReceived(RequestMessage message) 
{
    &lt;SPAN class=kwrd&gt;switch&lt;/SPAN&gt; (message.RequestAction) 
    {
        &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; RequestMessage.Action.PauseMedia:
            _wmcHost.MediaCenterEnvironment.MediaExperience.Transport.PlayRate = PlayRates.PLAYRATE_PAUSE;
            &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;
        &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; RequestMessage.Action.VolumeUp:
            _wmcHost.MediaCenterEnvironment.AudioMixer.VolumeUp();
            &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;
        &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; RequestMessage.Action.VolumeDown:
            _wmcHost.MediaCenterEnvironment.AudioMixer.VolumeDown();
            &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;
        &lt;SPAN class=kwrd&gt;case&lt;/SPAN&gt; RequestMessage.Action.NextMedia:
            _wmcHost.MediaCenterEnvironment.MediaExperience.Transport.SkipForward();
            &lt;SPAN class=kwrd&gt;break&lt;/SPAN&gt;;
    }
    SendAcknowledgement(message);
}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100%
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The RequestMessage class shown above is a custom object, originally created by Windows Mobile 5 application running on a connected mobile device. The transport object was then serialized on the device, transmitted, deserialized in the listener service, and raised to the add-in class via the MessageReceived event. The RequestAction property is an enumerable type indicating the type of action to take within Media Center. The Media Center API exposed by the AddInHost object (_wmcHost) can then be used to actually perform the desired Media Center operation. Finally, we send an acknowledgement message to the mobile device.&lt;BR&gt;
&lt;H3&gt;Implementing the Windows Mobile 5 remote client application&lt;/H3&gt;After completing the Media Center add-in, the mobile application is relatively simple by comparison. The remote application’s role is to present the user with a user interface similar to that of an actual remote control. The remote application directs user input to the listener add-in, and displays any response data if necessary. 
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;H4&gt;Implementing the socket client&lt;/H4&gt;
&lt;P&gt;The design of the socket client is much simpler than that of the socket server. All execution will be performed on the primary thread. The client begins by establishing a connection with an add-in server. Once established, the socket client sends and receives data synchronously over the socket. Consumers of the socket client need only call the Send method, which will return with the transactional response: &lt;/P&gt;
&lt;H5&gt;Visual Basic .NET&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Function&lt;/SPAN&gt; Send(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; request &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Message) &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; responseString &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt; = &lt;SPAN class=kwrd&gt;Nothing&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;Try&lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; ((&lt;SPAN class=kwrd&gt;Not&lt;/SPAN&gt; (_socket) &lt;SPAN class=kwrd&gt;Is&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Nothing&lt;/SPAN&gt;) _
                    &lt;SPAN class=kwrd&gt;AndAlso&lt;/SPAN&gt; _socket.Connected) &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; requestString &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt; = request.Serialize
            Send(requestString)
            responseString = RecvSynchronous
            &lt;SPAN class=kwrd&gt;Return&lt;/SPAN&gt; responseString
        &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;Catch&lt;/SPAN&gt; ex &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; Exception
        &lt;SPAN class=kwrd&gt;Return&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Nothing&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Try&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;Return&lt;/SPAN&gt; responseString
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Function&lt;/SPAN&gt;
&lt;/PRE&gt;
&lt;H5&gt;Visual C#&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; Send(Message request)
{
    &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; responseString = &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;;
    &lt;SPAN class=kwrd&gt;try&lt;/SPAN&gt;
    {
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (_socket != &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt; &amp;amp;&amp;amp; _socket.Connected)
        {
            &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; requestString = request.Serialize();
            Send(requestString);
            responseString = RecvSynchronous();
            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; responseString;
        }
    }
    &lt;SPAN class=kwrd&gt;catch&lt;/SPAN&gt; (Exception ex)
    {
        &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt;;
    }
    &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; responseString;
}
&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100%
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;H4&gt;Adding the UI layer&lt;/H4&gt;With the communications layer in place the next step in our remote implementation is the user interface. In this final stage, we hook up UI controls to construct the request messages that will be sent to the host service. However, before we do that we must first connect with the Media Center host machine. Here’s a look at the connection configuration screen: 
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/7_Config2.jpg" atomicselection="true" mce_href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/7_Config2.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" border=0 src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/7_Config_thumb.jpg" width=239 height=319 mce_src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/7_Config_thumb.jpg"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Figure 6 - The configuration screen on the mobile device&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;Once we’ve specified the host and port of our running Media Center add-in service, we can click the “Connect” button to initialize the TCP/IP socket connection. Using the TCP Client class developed earlier, the code required to handle this event is simple:&lt;/P&gt;
&lt;H5&gt;Visual Basic .NET&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; btnConnect_Click(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; sender &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Object&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; e &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; EventArgs)
    &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; host &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt; = &lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.txtHost.Text.Trim
    &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; port &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt; = &lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.txtPort.Text.Trim
    _client.Connect(host, Convert.ToInt32(port))
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; Sub&lt;/PRE&gt;
&lt;H5&gt;Visual C#&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; btnConnect_Click(&lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt; sender, EventArgs e)
{
     &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; host = &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.txtHost.Text.Trim();
     &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; port = &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.txtPort.Text.Trim();
     _client.Connect(host, Convert.ToInt32(port));
}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100%
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;Once connected, the user can navigate the application using the provided tabs at the bottom of the screen. Since this application is intended to function as a remote control, there is a standard media control screen:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/8_Controls2.jpg" atomicselection="true" mce_href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/8_Controls2.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" border=0 src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/8_Controls_thumb.jpg" width=241 height=319 mce_src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/8_Controls_thumb.jpg"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Figure 8: The control screen on the mobile device&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;Nothing exotic here, but the basic media control functionality you’d expect from a remote is available. Here’s a sample of the code required to support the “Stop” button’s click event:&lt;/P&gt;
&lt;H5&gt;Visual Basic .NET&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; btnConnect_Click(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; sender &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Object&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; e &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; EventArgs)
    &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; host &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt; = &lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.txtHost.Text.Trim
    &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; port &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt; = &lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.txtPort.Text.Trim
    _client.Connect(host, Convert.ToInt32(port))
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; Sub&lt;/PRE&gt;
&lt;H5&gt;Visual C#&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; btnStop_Click(&lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt; sender, EventArgs e)
{
    RequestMessage message = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; RequestMessage();
    message.RequestAction = RequestMessage.Action.StopMedia;
    message.Data = String.Empty;
    &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; responseString = client.Send(message);
    ResponseMessage response = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; ResponseMessage(responseString);
}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100%
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;The UI form uses the connected Client object to execute the Stop command. First, the form constructs a Request message, populating the type of action desired (StopMedia). Next, the Request message is passed to the Client class, where it is serialized for transport and sent over the connected TCP socket. From there, the running Media Center service will receive the request, perform the media stop, and send an acknowledgement. The Client then returns a Response message, which will contain a Boolean indicating if the request was successful or not. 
&lt;P&gt;On a Media Stop request, examining the Response object is not very informative. However, for other commands, the Media Center add-in service can be designed to return any kind of information required of the host. The Detail screen is a good example: 
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/9_Detail2.jpg" atomicselection="true" mce_href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/9_Detail2.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" border=0 src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/9_Detail_thumb.jpg" width=240 height=321 mce_src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/9_Detail_thumb.jpg"&gt;&lt;/A&gt; 
&lt;P&gt;&lt;EM&gt;Figure 9 - The detail page&amp;nbsp;&lt;/EM&gt; 
&lt;P&gt;When a song or video is currently playing, the above screen can be used to retrieve any metadata associated with it. The event handler for the screen’s “Refresh” button looks similar in form to the Stop button’s handler: 
&lt;H5&gt;Visual Basic .NET&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; btnRefreshDetail_Click(&lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; sender &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Object&lt;/SPAN&gt;, &lt;SPAN class=kwrd&gt;ByVal&lt;/SPAN&gt; e &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; EventArgs)
    &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; request &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; RequestMessage = &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; RequestMessage
    request.RequestAction = RequestMessage.Action.GetMediaMetadata
    &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; responseString &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt; = _client.Send(request)
    &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; response &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; MediaMetadataMessage = &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; MediaMetadataMessage(responseString)
    &lt;SPAN class=kwrd&gt;For&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Each&lt;/SPAN&gt; item &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; MediaMetadataMessage.MediaMetadataItem &lt;SPAN class=kwrd&gt;In&lt;/SPAN&gt; message.Data
        &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt; ((&lt;SPAN class=kwrd&gt;Not&lt;/SPAN&gt; (item.Value) &lt;SPAN class=kwrd&gt;Is&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Nothing&lt;/SPAN&gt;) &lt;SPAN class=kwrd&gt;AndAlso&lt;/SPAN&gt; (item.Value.Length &amp;gt; 0)) &lt;SPAN class=kwrd&gt;Then&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.txtDetail.Text = (&lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.txtDetail.Text + (item.Key + (&lt;SPAN class=str&gt;": "&lt;/SPAN&gt; + item.Value)))
            &lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.txtDetail.Text = (&lt;SPAN class=kwrd&gt;Me&lt;/SPAN&gt;.txtDetail.Text + &lt;SPAN class=str&gt;""&lt;/SPAN&gt; &amp;amp; vbCrLf)
        &lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;If&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;Next&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; Sub&lt;/PRE&gt;
&lt;H5&gt;Visual C#&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; btnRefreshDetail_Click(&lt;SPAN class=kwrd&gt;object&lt;/SPAN&gt; sender, EventArgs e)
{
    RequestMessage request = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; RequestMessage();
    request.RequestAction = RequestMessage.Action.GetMediaMetadata;
    &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; responseString = _client.Send(request);
    MediaMetadataMessage response = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; MediaMetadataMessage(responseString);
    &lt;SPAN class=kwrd&gt;foreach&lt;/SPAN&gt; (MediaMetadataMessage.MediaMetadataItem item &lt;SPAN class=kwrd&gt;in&lt;/SPAN&gt; message.Data) {
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; (item.Value != &lt;SPAN class=kwrd&gt;null&lt;/SPAN&gt; &amp;amp;&amp;amp; item.Value.Length &amp;gt; 0){
            &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.txtDetail.Text += item.Key + &lt;SPAN class=str&gt;": "&lt;/SPAN&gt; + item.Value;
            &lt;SPAN class=kwrd&gt;this&lt;/SPAN&gt;.txtDetail.Text += &lt;SPAN class=str&gt;"\r\n"&lt;/SPAN&gt;;
        }
    }
}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100%
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;This time, however, the Response object has a list of metadata keys and values, which are then enumerated and displayed in a textbox. This Response object was originally populated by the Media Center add-in service: 
&lt;H5&gt;Visual Basic .NET&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;Private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Sub&lt;/SPAN&gt; SendMediaMetadata()
    &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; response &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; MediaMetadataMessage()
    &lt;SPAN class=kwrd&gt;Dim&lt;/SPAN&gt; val &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt;
    &lt;SPAN class=kwrd&gt;For&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;Each&lt;/SPAN&gt; key &lt;SPAN class=kwrd&gt;As&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;String&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;In&lt;/SPAN&gt; _wmcHost.MediaCenterEnvironment.MediaExperience.MediaMetadata.Keys
    val = _wmcHost.MediaCenterEnvironment.MediaExperience.MediaMetadata.Item(key).ToString()
    response.Data.Add(&lt;SPAN class=kwrd&gt;New&lt;/SPAN&gt; MediaMetadataMessage.MediaMetadataItem(key, val))
    &lt;SPAN class=kwrd&gt;Next&lt;/SPAN&gt;
    response.ResponseIndicator = MediaMetadataMessage.ResponseCode.Success
    _server.Send(response)
&lt;SPAN class=kwrd&gt;End&lt;/SPAN&gt; Sub&lt;/PRE&gt;
&lt;H5&gt;Visual C#&lt;/H5&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;private&lt;/SPAN&gt; &lt;SPAN class=kwrd&gt;void&lt;/SPAN&gt; SendMediaMetadata() 
{
    MediaMetadataMessage response = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; MediaMetadataMessage();
    &lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; val;
    &lt;SPAN class=kwrd&gt;foreach&lt;/SPAN&gt; (&lt;SPAN class=kwrd&gt;string&lt;/SPAN&gt; key &lt;SPAN class=kwrd&gt;in&lt;/SPAN&gt; _wmcHost.MediaCenterEnvironment.MediaExperience.MediaMetadata.Keys) 
    {
        val = _wmcHost.MediaCenterEnvironment.MediaExperience.MediaMetadata.Item[key].ToString();
        response.Data.Add(&lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; MediaMetadataMessage.MediaMetadataItem(key, val));
    }
    response.ResponseIndicator = MediaMetadataMessage.ResponseCode.Success;
    _server.Send(response);
}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	BACKGROUND-COLOR: #ffffff; FONT-FAMILY: consolas, "Courier New", courier, monospace; COLOR: black; FONT-SIZE: small
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; WIDTH: 100%
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;After receiving a request from the mobile device for the currently playing media’s metadata, the Media Center add-in service constructs a list of custom objects (MediaMetadataItem). It populates this list by enumerating properties of the AddInHost object, through the namespace MediaCenterEnvironment.MediaExperience.MediaMetadata. It then sends this list on the Response object, where the mobile device will inspect and display the data, as shown above. 
&lt;P&gt;The last feature that the mobile remote application provides is the ability to select specific media to play based on a list of available media on the host. This functionality is provided for audio, video, and images: 
&lt;P&gt;&lt;A href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/10_Music2.jpg" atomicselection="true" mce_href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/10_Music2.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" border=0 src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/10_Music_thumb.jpg" width=240 height=320 mce_src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/10_Music_thumb.jpg"&gt;&lt;/A&gt; &lt;A href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/11_Video2.jpg" atomicselection="true" mce_href="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/11_Video2.jpg"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" border=0 src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/11_Video_thumb.jpg" width=240 height=320 mce_src="http://www.coding4fun.net/images/ControlWindowsMediaCenterusingaWindowsMo_A439/11_Video_thumb.jpg"&gt;&lt;/A&gt; 
&lt;P&gt;&lt;EM&gt;Figure 10 - Music and Video&amp;nbsp;list management&amp;nbsp;&lt;/EM&gt; 
&lt;P&gt;The mobile application requests the list of available media in a similar fashion to the Details screen implementation. The resulting list of files is then bound and displayed in a DataGrid. The Media Center add-in service can then be instructed to play individual songs or videos using the AddInHost’s MediaCenterEnvironment.PlayMedia method. &lt;/P&gt;
&lt;H4&gt;&lt;STRONG&gt;Mobile Application UI design considerations&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P&gt;Developing on the mobile platform introduces design challenges not found in Windows Forms applications due to the small amount of screen real estate available. Many typical form layouts found in Windows Forms applications won’t work well on a mobile device’s small screen. When developing for a mobile application, try to keep the user interface as simple as possible. Window containers and managers such as a tabbed control enable the developer to functionally divide an application into logical components. This alleviates the clutter created by having too many controls in a single window. Also try to keep your text and controls as simple and large as possible. This makes the application easier to view and manipulate, especially in outdoor or bright conditions.&lt;/P&gt;
&lt;H3&gt;Conclusion&lt;/H3&gt;
&lt;P&gt;Once complete, the remote application gives you a level of control simply not available on hardware-based remote controls. I really enjoyed working on this application because it gave me a chance to integrate a number of different technologies into a single implementation. Be sure to download the code and take the remote for a spin. For those not familiar with all of the components used in this article (Media Center add-in services, socket communication, installer and assembly signing, etc.), don’t be intimidated. The Microsoft-provided SDK packages for both parts of the solution make creating your own add-in projects a snap. Plus, the technical challenges unique to this project have already been overcome! Feel free to modify my implementation, or reuse the included socket classes to create an add-in all your own. Finally, please post feedback or questions here or at my &lt;A href="http://blogs.claritycon.com/blogs/matt_ivers/default.aspx" mce_href="http://blogs.claritycon.com/blogs/matt_ivers/default.aspx"&gt;blog&lt;/A&gt;.&lt;/P&gt;
&lt;H3&gt;About the Author&lt;/H3&gt;
&lt;P&gt;Matt Ivers is a software engineer at Chicago-based &lt;A href="http://www.claritycon.com/" mce_href="http://www.claritycon.com/"&gt;Clarity Consulting&lt;/A&gt;. He has extensive professional experience developing .NET solutions in both Visual C# .NET and VB.NET. Check him out at his &lt;A href="http://blogs.claritycon.com/blogs/matt_ivers/default.aspx" mce_href="http://blogs.claritycon.com/blogs/matt_ivers/default.aspx"&gt;blog&lt;/A&gt; or through the Clarity blog site, &lt;A href="http://blogs.claritycon.com/" mce_href="http://blogs.claritycon.com/"&gt;Clarity Blogs&lt;/A&gt;. &lt;/P&gt;
&lt;H3&gt;References&lt;/H3&gt;
&lt;P&gt;&lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyId=A43EA0B7-B85F-4612-AA08-3BF128C5873E&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyId=A43EA0B7-B85F-4612-AA08-3BF128C5873E&amp;amp;displaylang=en"&gt;Windows Media Center SDK 5.0&lt;/A&gt;&lt;BR&gt;&lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyID=dc6c00cb-738A-4B97-8910-5cd29ab5f8d9&amp;amp;DisplayLang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=dc6c00cb-738A-4B97-8910-5cd29ab5f8d9&amp;amp;DisplayLang=en"&gt;Windows Mobile 5.0 Smartphone SDK&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/ms247123(VS.80).aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms247123(VS.80).aspx"&gt;How to: Sign an Assembly using Visual Studio 2005&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/MedctrSDK/htm/creatingawindowsinstallerfileforanaddin.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/MedctrSDK/htm/creatingawindowsinstallerfileforanaddin.asp"&gt;How to: Create a Windows Installer File for a Windows Media Center Add-in&lt;/A&gt; 
&lt;P&gt;&lt;A href="http://msdn2.microsoft.com/en-gb/library/ms816327.aspx" mce_href="http://msdn2.microsoft.com/en-gb/library/ms816327.aspx"&gt;Windows Media Center - SDK Overview&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/bb189667.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb189667.aspx"&gt;Windows Media Center - Understanding the Basics&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/bb189733.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb189733.aspx"&gt;Windows Media Center - Development Tools&lt;/A&gt;&lt;BR&gt;&lt;A href="http://msdn.microsoft.com/smartclient/default.aspx?pull=/library/en-us/dnxpmce/html/positionchangeraddin.asp" mce_href="http://msdn.microsoft.com/smartclient/default.aspx?pull=/library/en-us/dnxpmce/html/positionchangeraddin.asp"&gt;Windows Media Center - AddIn example: "Time Travel"&lt;/A&gt; 
&lt;P&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/5w7b7x5f.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/5w7b7x5f.aspx"&gt;Using an Asynchronous Server Socket&lt;/A&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=2632164" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/media/default.aspx">media</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/home+automation/default.aspx">home automation</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/audiovideo/default.aspx">audiovideo</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/hardwarehacks/default.aspx">hardwarehacks</category></item><item><title>Controlling Your Lights with Your PC</title><link>http://blogs.msdn.com/coding4fun/archive/2006/12/20/1337418.aspx</link><pubDate>Thu, 21 Dec 2006 05:59:06 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1337418</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>22</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/1337418.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=1337418</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=1337418</wfw:comment><description>&lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;b&gt;Chris Walker&lt;br&gt;ControlThink LC&lt;/b&gt;&lt;b&gt;&lt;/b&gt;  &lt;p&gt;&lt;b&gt;Difficulty: &lt;/b&gt;Easy &lt;p&gt;&lt;b&gt;Time Required:&lt;/b&gt; 1-3 hours &lt;p&gt;&lt;b&gt;Cost: &lt;/b&gt;$50-$100 &lt;p&gt;&lt;b&gt;Software: &lt;a href="http://www.controlthink.com"&gt;Z-Wave PC SDK&lt;/a&gt;&lt;/b&gt; &lt;p&gt;&lt;a href="http://msdn.com/express/"&gt;&lt;/a&gt;&lt;strong&gt;Hardware:&lt;/strong&gt; &lt;a href="http://www.controlthink.com"&gt;Z-Wave PC SDK&lt;/a&gt; &lt;p&gt;&lt;b&gt;Download: &lt;/b&gt; &lt;ul&gt; &lt;li&gt;&lt;a href="http://channel9.msdn.com/ShowPost.aspx?PostID=267636"&gt;C# Download&lt;/a&gt; &lt;li&gt;&lt;a href="http://channel9.msdn.com/ShowPost.aspx?PostID=267637"&gt;VB Download&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;b&gt;December 20, 2006&lt;/b&gt;  &lt;p&gt;Controlling your lights with a remote is pretty cool, but doing it from your PC opens up a whole world of fun possibilities.  &lt;p&gt;In this article, we’ll add your computer to the Z-Wave network which we set up in the previous article. We’ll run software to demonstrate how to set up and activate scenes with the PC. And then we’ll see how easy it is to write our own code and totally personalize the system.  &lt;p&gt;&lt;b&gt;What you need&lt;/b&gt;  &lt;p&gt;For this project, you’ll need a copy of ThinkEssentials, our Z-Wave PC SDK, and a compatible Z-Wave USB Stick. Here, we’ll use the Z-Wave PC SDK bundle which includes all three. You can get it for $69 from &lt;a href="http://www.controlthink.com/"&gt;http://www.controlthink.com&lt;/a&gt;.  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/ControllingYourLightswithYourPC_12727/clip_image0014.jpg" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="160" alt="usbstick" src="http://www.coding4fun.net/images/ControllingYourLightswithYourPC_12727/clip_image0013.jpg" width="240" border="0"&gt;&lt;/a&gt;Intermatic’s HA22 USB Stick; we’ll plug this into our computer.  &lt;p&gt;Once you have the kit, simply plug the Z-Wave USB stick into your PC. If a USB extension cable was provided, plug the USB stick into it instead and then move the USB stick away from walls and metal objects for best reception. Finally, install the USB stick drivers and both software products (all of which are on the CD).  &lt;p&gt;Now that the software and hardware are installed, we’re ready to get started.  &lt;p&gt;&lt;b&gt;Adding your computer to the Z-Wave network&lt;/b&gt;  &lt;p&gt;To add your computer to the network we set up in the previous article, we’ll use the ThinkEssentials software (although you can also join a network with a line or two of code—see the &lt;a href="http://channel9.msdn.com/ShowPost.aspx?PostID=267638"&gt;Z-Wave PC SDK Primer sample code&lt;/a&gt; ). Go ahead and start the software up now. Then, switch to the Advanced Settings tab on the left side of the screen.  &lt;p&gt;If you haven’t set up your Z-Wave network with a remote already, you could set it up with your PC instead--using the ThinkEssentials software or by writing some code. If you’d rather go that route, you can find full details in the &lt;a href="http://channel9.msdn.com/ShowPost.aspx?PostID=267638"&gt;Z-Wave PC SDK Primer&lt;/a&gt; .  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/ControllingYourLightswithYourPC_12727/clip_image0024.gif" atomicselection="true"&gt;&lt;img height="120" alt="AdvancedSettingsTab.gif" src="http://www.coding4fun.net/images/ControllingYourLightswithYourPC_12727/clip_image0023.gif" width="240" border="0"&gt;&lt;/a&gt;&lt;br&gt;The ThinkEssentials Advanced Settings tab; we’ll add our computer to the network here.  &lt;p&gt;On the Advanced Settings tab, click the “Join Existing Network” button. This will put our USB stick into a mode where it can be added into an existing network. On your HA09 (Tabletop Remote), flip open its lid and press and hold the INCLUDE button for a few seconds until it displays “COPY”. If you have an HA07 (Handy Remote) instead, hold down INCLUDE until the red and green LEDs start flashing. Finally, press the CHANNEL 1 ON button to start adding your PC to the network. This process may take five or ten seconds to get started.  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/ControllingYourLightswithYourPC_12727/clip_image0034.jpg" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="120" alt="joinnetwork.jpg" src="http://www.coding4fun.net/images/ControllingYourLightswithYourPC_12727/clip_image0033.jpg" width="240" border="0"&gt;&lt;/a&gt;&lt;br&gt;The JOIN EXISTING NETWORK button (left); holding the INCLUDE button (right)  &lt;p&gt;Once your computer is added to the network, ThinkEssentials may close automatically and save the changes. Simply restart the software.  &lt;p&gt;&lt;b&gt;Controlling your devices from the PC&lt;/b&gt;  &lt;p&gt;Switch to the Home tab in ThinkEssentials, and you’ll see icons for each of your devices at the bottom-right corner of the window. To turn them on or off, simply click on them. Go ahead, try this now. If you have lamp modules or dimmable light switches, simply right-click on them for dimming options.  &lt;p&gt;If you’d like, you can also draw your home’s floor plan, set up mood lighting (scenes), set up scheduled events for those scenes, etc. I’ll leave these to your experimentation; if you need any guidance, a shortcut to the User’s Guide is included in the Start Menu Programs folder alongside the software.  &lt;p&gt;&lt;b&gt;Turning on lights from Visual Basic Express or Visual C# Express&lt;/b&gt;  &lt;p&gt;When you’re done experimenting with the ThinkEssentials software, go ahead and close it so we can use the Z-Wave USB stick from Visual Studio Express. You can download Microsoft’s Visual Studio Express. If you’ve set up any scheduled events, you’ll need to right-click on the software’s system tray icon and select “Exit” from the pop-up menu.  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/ControllingYourLightswithYourPC_12727/clip_image0044.jpg" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="96" alt="trayexit.jpg" src="http://www.coding4fun.net/images/ControllingYourLightswithYourPC_12727/clip_image0043.jpg" width="240" border="0"&gt;&lt;/a&gt;&lt;br&gt;To completely shut down ThinkEssentials, right-click on its tray icon and click Exit.  &lt;p&gt;Now, we’re ready to get started controlling our lights using Visual Studio Express. With Visual Studio Express, we can personalize our home in unlimited ways. For now, we’ll start out simple and turn on the lights.  &lt;p&gt;&lt;b&gt;Creating our Visual Basic Express and Visual C# Express project&lt;/b&gt;  &lt;p&gt;With this sample, we’re going to turn on all of our lights. So to prepare for this sample, go ahead and turn off all the lights connected to Z-Wave devices (plug-in modules).  &lt;p&gt;Then, start up Visual Basic Express or Visual C# Express. Create a Windows Application named “TurnOnLights”. Once you’ve created the project, select “Add Reference…” from the Project menu, switch to the dialog’s Browse tab, and then add in the ControlThink.ZWave.dll file that came with the Z-Wave PC SDK. If you don’t know where it is, look in your Program Files folder for a ControlThink and Z-Wave PC SDK folder.  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/ControllingYourLightswithYourPC_12727/clip_image0054.gif" atomicselection="true"&gt;&lt;img height="153" alt="addreference.gif" src="http://www.coding4fun.net/images/ControllingYourLightswithYourPC_12727/clip_image0053.gif" width="240" border="0"&gt;&lt;/a&gt;&lt;br&gt;To add the Z-Wave assembly to the project, select Add Reference from the Project menu…  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/ControllingYourLightswithYourPC_12727/clip_image0064.gif" atomicselection="true"&gt;&lt;img height="190" alt="BrowseForDll.gif" src="http://www.coding4fun.net/images/ControllingYourLightswithYourPC_12727/clip_image0063.gif" width="240" border="0"&gt;&lt;/a&gt;&lt;br&gt;In the Add Reference dialog, change to the Browse tab and then add in ControlThink.ZWave.dll.  &lt;p&gt;Once you have added in the Z-Wave assembly, double-click on the default form; this should open up the Form_Load method in code. Once there, we’ll create an instance of the ZWaveController object. This will let us connect to our Z-Wave network with the USB stick. In the Form_Load method, add the following code:  &lt;p&gt;&lt;b&gt;Visual Basic&lt;/b&gt;  &lt;p&gt;Dim zwaveController As New ControlThink.ZWave.ZWaveController()  &lt;p&gt;&lt;b&gt;Visual C#&lt;/b&gt;  &lt;p&gt;ControlThink.ZWave.ZWaveController zwaveController = new ControlThink.ZWave.ZWaveController();  &lt;p&gt;Next, we’ll connect to the network. It only takes two lines of code to get “online” with the home.  &lt;p&gt;&lt;b&gt;Visual Basic&lt;/b&gt;  &lt;p&gt;zwaveController.Connect()  &lt;p&gt;&lt;b&gt;Visual C#&lt;/b&gt;  &lt;p&gt;zwaveController.Connect();  &lt;p&gt;Now that we’ve created the necessary code to connect to the network through our Z-Wave USB stick, we’ll add just a few more lines of code to turn on all the lights. Every device in our network is ultimately based on the ZWaveDevice object, and this class gives us the ability to turn on and off devices as well as change their dim level so we’ll use it here.  &lt;p&gt;Let’s also include a Try…Catch block here; our remotes and some other devices cannot be turned on and off and consequently throw an exception if we try.  &lt;p&gt;&lt;b&gt;Visual Basic&lt;/b&gt;  &lt;p&gt;For Each device As ControlThink.ZWave.Devices.ZWaveDevice In zwaveController.Devices  &lt;p&gt;Try  &lt;p&gt;device.PowerOn()  &lt;p&gt;Catch ex As Exception  &lt;p&gt;End Try  &lt;p&gt;Next  &lt;p&gt;&lt;b&gt;Visual C#&lt;/b&gt;  &lt;p&gt;&lt;b&gt;&lt;br&gt;&lt;/b&gt;foreach(ControlThink.ZWave.Devices.ZWaveDevice device in zwaveController.Devices)  &lt;p&gt;{  &lt;p&gt;try  &lt;p&gt;{  &lt;p&gt;device.PowerOn();  &lt;p&gt;}  &lt;p&gt;catch(Exception ex)  &lt;p&gt;{}  &lt;p&gt;}  &lt;p&gt;That’s it. Run your code, and watch your lights turn on!  &lt;p&gt;Of course, you can also turn everything off. To do that instead, just change the PowerOn method to PowerOff:  &lt;p&gt;&lt;b&gt;Visual Basic&lt;/b&gt;  &lt;p&gt;For Each device As ControlThink.ZWave.Devices.ZWaveDevice In zwaveController.Devices  &lt;p&gt;Try  &lt;p&gt;device.PowerOff()  &lt;p&gt;Catch ex As Exception  &lt;p&gt;End Try  &lt;p&gt;Next  &lt;p&gt;&lt;b&gt;Visual C#&lt;/b&gt;  &lt;p&gt;&lt;b&gt;&lt;br&gt;&lt;/b&gt;foreach(ControlThink.ZWave.Devices.ZWaveDevice device in zwaveController.Devices)  &lt;p&gt;{  &lt;p&gt;try  &lt;p&gt;{  &lt;p&gt;device.PowerOff();  &lt;p&gt;}  &lt;p&gt;catch(Exception ex)  &lt;p&gt;{}  &lt;p&gt;}  &lt;p&gt;&lt;b&gt;What to try next&lt;/b&gt;  &lt;p&gt;Now that you’ve experienced the basics of using Z-Wave from Visual Studio Express, here are a few ideas you can use to personalize your own home:  &lt;p&gt;1. device.Level can be set to 0 for off, or 1-99 for dim levels (99 = full on).  &lt;p&gt;2. zwaveController.Devices is a collection of all the devices in your network. Each of those devices has a unique ID on the network called a Node ID. Access the devices individually by index, or use zwaveController.Devices.GetByNodeID(…) to access each device by its unique Node ID.  &lt;p&gt;3. &lt;a href="http://msdn.microsoft.com/coding4fun/windows/utility/article.aspx?articleid=908744&amp;amp;title=Creating+an+Alarm+Clock+in+the+System+Tray"&gt;Alarm Clock&lt;/a&gt; sample from Coding4Fun, and customize it to turns up the heating set point 30 minutes before the alarm goes off.  &lt;p&gt;&lt;b&gt;About the author&lt;/b&gt;  &lt;p&gt;Chris Walker is President and Chief Software Architect of &lt;a href="http://www.controlthink.com/"&gt;ControlThink&lt;/a&gt;, creator of the Z-Wave SDKs for .NET platforms, and is an outspoken advocate of reliable home control technology. He is determined to make home control technology easy to use and affordable for all homeowners.  &lt;span style='display:none'&gt;&lt;![CDATA[ &lt;summary&gt; &lt;title&gt;Controlling Your Lights with Your PC&lt;/title&gt; &lt;description&gt;&lt;![CDATA[ Controlling your lights with a remote is pretty cool, but doing it from your PC opens up a whole world of fun possibilities.  In this article, we’ll add your computer to the Z-Wave network which we set up in the previous article. We’ll run software to demonstrate how to set up and activate scenes with the PC. And then we’ll see how easy it is to write our own code and totally personalize the system.]]&gt;&lt;/description&gt; &lt;author&gt; &lt;name&gt;Chris Walker&lt;/name&gt; &lt;company&gt;&lt;/company&gt; &lt;url&gt;&lt;/url&gt; &lt;/author&gt; &lt;downloads&gt; &lt;csharp&gt;http://channel9.msdn.com/ShowPost.aspx?PostID=267636&lt;/csharp&gt; &lt;vb&gt;http://channel9.msdn.com/ShowPost.aspx?PostID=267637&lt;/vb&gt; &lt;/downloads&gt; &lt;difficulty&gt;Easy&lt;/difficulty&gt; &lt;requirements&gt; &lt;cost&gt;$50-$100&lt;/cost&gt; &lt;time&gt;1-3 hours&lt;/time&gt; &lt;software&gt;&lt;![CDATA[&lt;a href="http://www.controlthink.com"&gt;Z-Wave PC SDK&lt;/a&gt;]]&gt;&lt;/software&gt; &lt;hardware&gt;&lt;![CDATA[Z-Wave PC SDK]]&gt;&lt;/hardware&gt; &lt;/requirements&gt; &lt;/summary&gt; ]]&gt;&lt;/span&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1337418" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/home+automation/default.aspx">home automation</category></item><item><title>Decking Out Your Home Entertainment System with Theater-style Lighting</title><link>http://blogs.msdn.com/coding4fun/archive/2006/11/16/1088252.aspx</link><pubDate>Thu, 16 Nov 2006 22:22:35 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1088252</guid><dc:creator>Coding4Fun</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/coding4fun/comments/1088252.aspx</comments><wfw:commentRss>http://blogs.msdn.com/coding4fun/commentrss.aspx?PostID=1088252</wfw:commentRss><wfw:comment>http://blogs.msdn.com/coding4fun/rsscomments.aspx?PostID=1088252</wfw:comment><description>&lt;span id="c4fmetadata"&gt; &lt;table cellspacing="0" cellpadding="1" width="100%" border="0"&gt; &lt;tbody&gt; &lt;tr class="entry_overview"&gt; &lt;td width="50"&gt;&lt;img height="50" src="http://www.coding4fun.net/images/int_thumb.jpg" width="50"&gt;&lt;/td&gt; &lt;td&gt;&lt;span class="entry_description"&gt;This article walks through how to get that real movie theater feeling at home using the Intermatic HomeSettings Kit.&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td colspan="2"&gt; &lt;div class="entry_author"&gt;Chris Walker&lt;/div&gt; &lt;div class="entry_company"&gt;&lt;a href="http://www.controlthink.com/"&gt;ControlThink LC&lt;/a&gt;&lt;/div&gt;&lt;br&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Difficulty: &lt;/b&gt;&lt;span class="entry_details_input"&gt;Easy&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Time Required:&lt;/b&gt; &lt;span class="entry_details_input"&gt;Less than 1 hour&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Cost: &lt;/b&gt;&lt;span class="entry_details_input"&gt;$100-$200&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Software: &lt;/b&gt;&lt;span class="entry_details_input"&gt;None&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;&lt;b&gt;Hardware: &lt;/b&gt;&lt;span class="entry_details_input"&gt;&lt;a href="http://www.homesettings.com/"&gt;Intermatic Home Settings Kit&lt;/a&gt;&lt;/span&gt;&lt;/div&gt; &lt;div class="entry_details"&gt;Video: &lt;a href="http://channel9.msdn.com/ShowPost.aspx?PostID=259155"&gt;Watch the Channel9 Video&lt;/a&gt;&amp;nbsp;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/span&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;b&gt;&lt;/b&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;To deck out your home entertainment system, typical options include buying a bigger TV or a better speaker system. But for something really unique and cool, add automated lighting to yours for less than $100 to give it that real movie theater feeling.  &lt;p&gt;In just a few minutes, you’ll be dimming the lights when movies start and will have the coolest system around!  &lt;p&gt;&lt;b&gt;What you need&lt;br&gt;&lt;/b&gt;For this project, you’ll need a Z-Wave® remote control and two Z-Wave plug-in lamp modules. Here, we’ll use Intermatic®‘s HomeSettings™ Lighting Control Starter Kit (model HA101K). I found it for $99 at Lowes, although you can buy it at other retail stores or online.  &lt;p&gt;You’ll also need 4 AA batteries.  &lt;p&gt;NOTE: if your lighting is built-in and controlled by switches, you can pick up Z-Wave light switches from any manufacturer and use them instead of the plug-in modules—but you’ll want to follow the switches’ installation instructions or hire an electrician to wire those up.  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/DeckingOutYourHomeEntertainmentSystemwit_9F59/image0012.jpg" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="333" src="http://www.coding4fun.net/images/DeckingOutYourHomeEntertainmentSystemwit_9F59/image001_thumb.jpg" width="500" border="0"&gt;&lt;/a&gt;  &lt;p&gt;Intermatic’s HomeSettings Lighting Control Starter Kit (model HA101K)  &lt;p&gt;You’ll quickly notice that this system is wireless. There have been powerline home automation systems in the past, but those have often been plagued with reliability problems. But don’t let that worry you: Z-Wave devices are wireless and will even act as mesh-networked repeaters automatically. If you’re not familiar with how that works, just know that it’s quite a reliable system.  &lt;p&gt;&lt;b&gt;Hooking up the lights&lt;br&gt;&lt;/b&gt;Since we’re using plug-in modules here, there’s no need to break out voltage meters or screwdrivers. Simply plug the lamps into the modules and then plug the modules into the wall. Also, be sure to turn on the lamps themselves.  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/DeckingOutYourHomeEntertainmentSystemwit_9F59/image0022.jpg" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="250" src="http://www.coding4fun.net/images/DeckingOutYourHomeEntertainmentSystemwit_9F59/image002_thumb.jpg" width="500" border="0"&gt;&lt;/a&gt;  &lt;p&gt;Plugging lamp into module (left); module plugged into wall outlet (right)  &lt;p&gt;&lt;b&gt;Adding the lights to the remote&lt;br&gt;&lt;/b&gt;Now, we just need to add the lamp modules to the remote control. Make sure there are batteries in the remote, and flip it open to reveal the INCLUDE and DELETE buttons.  &lt;p&gt;To add a lamp module to the remote, simply press and release the INCLUDE button. The display will show a small “INCL” indicator in the top-right corner of the LCD and will flash “TRANSMITTING.” Then, press the button on the lamp module. The remote should flash “SUCCESSFUL” indicating that it now recognizes your module. You have just paired the lamp module with your remote!  &lt;p&gt;Go ahead and repeat this now with your second lamp module.  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/DeckingOutYourHomeEntertainmentSystemwit_9F59/image0042.jpg" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="220" src="http://www.coding4fun.net/images/DeckingOutYourHomeEntertainmentSystemwit_9F59/image004_thumb.jpg" width="500" border="0"&gt;&lt;/a&gt;  &lt;p&gt;Pressing the INCLUDE button (left); pressing the button on the device (right)  &lt;p&gt;&lt;b&gt;Setting up the lighting scene&lt;br&gt;&lt;/b&gt;For our home theater experience, we want to fade the lights off when we start the movie and turn them back on just slightly when the movie is over so that we don’t blind our movie-watching guests.  &lt;p&gt;Let’s add the lamp modules to scene one on the remote. This is a quick three step process.  &lt;p&gt;NOTE: there are six sets of scene buttons (on and off for each scene) on this remote. Pressing the SHIFT button will switch to scenes 7 through 12, so make sure you’re currently looking at scenes 1 through 6; if you’re not, simply press the SHIFT button.  &lt;p&gt;First, simultaneously press and hold both the ON and OFF buttons for scene one. After holding down these two buttons for three or four seconds, the display will show “LEARN” in big text. Now, press and hold the INCLUDE button—and don’t let go of it quite yet.  &lt;p&gt;While you’re holding down the INCLUDE button, press the button on the lamp module to include in this scene. If the lamp module is off or turns off, press the button on the lamp module again to turn it on. When the lamp is on, go ahead and release the INCLUDE button on the remote. That’s it!  &lt;p&gt;Now, go ahead and repeat this process for the other lamp module, again using scene one.  &lt;p&gt;&lt;a href="http://www.coding4fun.net/images/DeckingOutYourHomeEntertainmentSystemwit_9F59/image0062.jpg" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="220" src="http://www.coding4fun.net/images/DeckingOutYourHomeEntertainmentSystemwit_9F59/image006_thumb.jpg" width="500" border="0"&gt;&lt;/a&gt;  &lt;p&gt;&lt;b&gt;&lt;br&gt;&lt;/b&gt;Pressing scene one’s ON and OFF buttons (left)&lt;b&gt;; &lt;/b&gt;pressing and holding the INCLUDE button (right)&lt;b&gt;&lt;/b&gt;  &lt;p&gt;&lt;b&gt;Settling in for the ultimate home theater experience&lt;br&gt;&lt;/b&gt;Now it’s time to grab your favorite movie and snack, gather your friends, and enjoy your new setup. To turn off the lights (with nifty ramping effect), press scene one’s OFF button. When the movie is over, press the ON button. If you want to dim the lights up or down, simply hold down the scene’s ON (dim up) or OFF (dim down) button respectively.  &lt;p&gt;&lt;b&gt;&lt;a href="http://www.coding4fun.net/images/DeckingOutYourHomeEntertainmentSystemwit_9F59/image0082.jpg" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="327" src="http://www.coding4fun.net/images/DeckingOutYourHomeEntertainmentSystemwit_9F59/image008_thumb.jpg" width="500" border="0"&gt;&lt;/a&gt; &lt;br&gt;&lt;/b&gt;Lights off! Pressing scene one’s OFF button sets the mood for “Batman Begins”…&lt;b&gt;&lt;/b&gt;  &lt;p&gt;&lt;b&gt;More cool things to do with your new setup&lt;br&gt;&lt;/b&gt;One of the great things about Z-Wave is that you can do new things with your existing devices and can add on new devices anytime. Here are a few cool things to do with your new setup:  &lt;p&gt;1. Set up a second scene with the lights at 20%; this will be good to switch to when the movie is over so you don’t blind your friends.  &lt;p&gt;2. When I’m tired, getting out of bed wakes me up. Set up your bedroom instead and enjoy this new convenience when going to bed (or getting up!)  &lt;p&gt;3. For an even better home theater experience, wire up your overhead lights—or add in motorized blinds. If it has the Z-Wave logo on it, it’ll work with your system.  &lt;p&gt;&lt;b&gt;About the author&lt;br&gt;&lt;/b&gt;Chris Walker is President and Chief Software Architect of &lt;a href="http://www.controlthink.com/"&gt;ControlThink&lt;/a&gt;, creator of the Z-Wave SDKs for .NET platforms, and is an outspoken advocate of reliable home control technology. He is determined to make home control technology affordable and available to the average homeowner.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1088252" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/coding4fun/archive/tags/home+automation/default.aspx">home automation</category><category domain="http://blogs.msdn.com/coding4fun/archive/tags/hardware/default.aspx">hardware</category></item></channel></rss>