<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Michael Hopcroft</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/mhop/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/mhop/feed.xml</link>
    <description />
    <lastBuildDate>Tue, 16 Apr 2019 05:18:28 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Home Automation Part 3 - Using Regular Expressions to Parse Sensor Data</title>
      <link>https://docs.microsoft.com/archive/blogs/mhop/home-automation-part-3-using-regular-expressions-to-parse-sensor-data</link>
      <pubDate>Mon, 08 Jan 2007 02:02:00 GMT</pubDate>
      <dc:creator><![CDATA[mhop]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mhop/2007/01/08/home-automation-part-3-using-regular-expressions-to-parse-sensor-data/</guid>
      <description><![CDATA[&#160;  In the previous installment I managed to set up basic communications with the sensor network...]]></description>
      <content:encoded><![CDATA[<p mce_keep="true">&#160;</p>  <p>In the <a title="Home Automation Part 2 – Making Basic Measurements" href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx" mce_href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx">previous installment</a> I managed to set up basic communications with the sensor network and try out some <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> commands using my <a title="Home Automation Part 2 – Making Basic Measurements" href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx" mce_href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx">Super-Simple Serial Console</a>. In order to actually do anything with the sensor data, I would need a function that could crack the <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> responses into sensor IDs and temperature and humidity values. </p>  <p>This seemed like a job for <a title="System.Text.RegularExpressions" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.aspx">System.Text.RegularExpressions</a>. My only problem was that no matter how carefully I constructed my regular expression, there would always be a bug. The edit-compile-test cycle was getting tedious so I decided to take a detour and code up a simple interactive regular expression tester using <a title="Windows Forms Applications" href="https://msdn2.microsoft.com/en-us/library/ms644558.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/ms644558.aspx">WinForms</a>. This post describes the regular expression tester and then explains how I used it to develop the regular expression necessary to extract the sensor ID, temperature, and humidity values from the <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> response string.</p>  <h3><strong>An Interactive Regular Expression Tester</strong></h3>  <p>My goal was to create a simple application that could show the results of a <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> in real time as I was editing the expression. I also wanted to prototype the <a title="Visual C#" href="https://msdn2.microsoft.com/en-us/library/kx37x362(VS.80).aspx" mce_href="https://msdn2.microsoft.com/en-us/library/kx37x362(VS.80).aspx">C#</a> code that I would need to navigate the <a title="System.Text.RegularExpressions.Regex class" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.regex.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.regex.aspx">Regex's</a> resulting hierarchy of <a title="System.Text.RegularExpressions.Match" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx">Matches</a>, <a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Groups</a>, and <a title="System.Text.RegularExpressions.Capture" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx">Captures</a> to pull out the values matched by my <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a>. If you develop a lot of <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expressions</a> you might consider using a more sophisticated and full featured application such as <a title="Chris Sells" href="https://www.sellsbrothers.com/" mce_href="https://www.sellsbrothers.com/">Chris Sells'</a> excellent <a title="RegexDesigner.NET" href="https://www.sellsbrothers.com/tools/#regexd" mce_href="https://www.sellsbrothers.com/tools/#regexd">RegexDesigner.NET</a>.</p>  <p>My simple application provides two text boxes, one for entering sample data and one for the regular expression (see Figure 1). Edits to either the sample data or the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> trigger an application of the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a>, the results of which are shown in the bottom pane in real time. </p>  <p><a href="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image01.png" mce_href="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image01.png"><img src="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image0_thumb1.png" width="523" height="449" mce_src="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image0_thumb1.png" /></a> </p>  <p><strong>Figure 1. A very simple interactive regular expression evaluator.</strong></p>  <p>The application is built in <a title="Windows Forms Applications" href="https://msdn2.microsoft.com/en-us/library/ms644558.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/ms644558.aspx">WinForms</a> using <a title="Visual C#" href="https://msdn2.microsoft.com/en-us/library/kx37x362(VS.80).aspx" mce_href="https://msdn2.microsoft.com/en-us/library/kx37x362(VS.80).aspx">C#</a>. You can find the complete source code and executable in an attachment at the end of this post. Here's a rough outline of the steps you would need to take to write a similar application:</p>  <ol>   <li>From <a href="https://msdn.microsoft.com/vstudio/vshome.aspx" mce_href="https://msdn.microsoft.com/vstudio/vshome.aspx">Visual Studio</a>, use File -&gt; New Project to create a Visual C# Windows Application. </li>    <li>In Form1.cs [design]      <ol>       <li>Set the window title to &quot;Interactive Regular Expression Evaluator&quot; </li>        <li>Add a <a title="System.Windows.Forms.Label" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformslabelclasstopic.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformslabelclasstopic.asp">Label</a> control with Text = &quot;Sample Data&quot; </li>        <li>Add a <a title="System.Windows.Forms.TextBox" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsTextBoxClassTopic.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsTextBoxClassTopic.asp">TextBox</a> control named <em><strong>SampleData</strong></em> to hold the sample input string. </li>        <li>Add another Label with Text = &quot;Regular Expression&quot; </li>        <li>Add a <a title="System.Windows.Forms.TextBox" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsTextBoxClassTopic.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsTextBoxClassTopic.asp">TextBox</a> named <strong><em>RegularExpression</em></strong> to hold the text of the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a>. </li>        <li>Add another <a title="System.Windows.Forms.Label" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformslabelclasstopic.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformslabelclasstopic.asp">Label</a> with Text = &quot;Results&quot; </li>        <li>Add a read-only <a title="System.Windows.Forms.TextBox" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsTextBoxClassTopic.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsTextBoxClassTopic.asp">TextBox</a> named <strong><em>Results</em></strong> to display the results of the expression application. </li>        <li>Set all <a title="System.Windows.Forms.TextBox" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsTextBoxClassTopic.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsTextBoxClassTopic.asp">TextBox</a> anchors to include <strong><a title="System.Windows.Forms.AnchorStyles Enumeration" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformsanchorstylesclasstopic.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformsanchorstylesclasstopic.asp">Top</a></strong>, <strong><strong><a title="System.Windows.Forms.AnchorStyles Enumeration" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformsanchorstylesclasstopic.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformsanchorstylesclasstopic.asp">Left</a></strong></strong>, and <strong><strong><a title="System.Windows.Forms.AnchorStyles Enumeration" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformsanchorstylesclasstopic.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformsanchorstylesclasstopic.asp">Right</a></strong></strong>. Set the anchor for the <strong><em>Results</em></strong> <a title="System.Windows.Forms.TextBox" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsTextBoxClassTopic.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsTextBoxClassTopic.asp">TextBox</a> to include <strong><strong><a title="System.Windows.Forms.AnchorStyles Enumeration" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformsanchorstylesclasstopic.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformsanchorstylesclasstopic.asp">Bottom</a></strong></strong>.</li>     </ol>   </li>    <li>Wire up the <a title="System.Windows.Forms.Control.TextChangedEvent" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformscontrolclasstextchangedtopic.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformscontrolclasstextchangedtopic.asp">TextChanged</a> event handlers for <strong><em>SampleData</em></strong> and <strong><em>RegularExpression</em></strong> to invoke a new method called <strong><em>ApplyRegularExpression()</em></strong>. </li>    <li>Modify the constructor of <strong><em>Form1</em></strong> to call <strong><em>ApplyRegularExpression()</em></strong> method on application startup. </li>    <li>Write the <strong><em>ApplyRegularExpression()</em></strong> method.</li>  </ol>  <p>The heart of the application is the <strong><em><strong><em>ApplyRegularExpression</em></strong>()</em></strong> method which is shown in Listing 1. Whenever the user changes either the sample data or the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a>, the <em><strong><strong><em>ApplyRegularExpression</em></strong>()</strong></em> method is invoked to update the results panel. Let's walk through the code. </p>  <p><strong>Listing 1. The <strong><em>ApplyRegularExpression</em></strong>() method updates the results panel whenever the sample data or regular expression changes.</strong></p>  <div class="csharpcode">   <pre><span class="lnum">   1:  </span><span class="kwrd">void</span> ApplyRegularExpression()</pre>

  <pre><span class="lnum">   2:  </span>{</pre>

  <pre><span class="lnum">   3:  </span>    <span class="kwrd">try</span></pre>

  <pre><span class="lnum">   4:  </span>    {</pre>

  <pre><span class="lnum">   5:  </span>        Results.Text = <span class="str">&quot;&quot;</span>;</pre>

  <pre><span class="lnum">   6:  </span>        <span class="kwrd">string</span> results = <span class="str">&quot;&quot;</span>;</pre>

  <pre><span class="lnum">   7:  </span>&#160;</pre>

  <pre><span class="lnum">   8:  </span>        Regex r = <span class="kwrd">new</span> Regex(RegularExpression.Text);</pre>

  <pre><span class="lnum">   9:  </span>        MatchCollection matches = r.Matches(SampleData.Text);</pre>

  <pre><span class="lnum">  10:  </span>        <span class="kwrd">for</span> (<span class="kwrd">int</span> i=0; i &lt; matches.Count; ++i)</pre>

  <pre><span class="lnum">  11:  </span>        {</pre>

  <pre><span class="lnum">  12:  </span>            Match m = matches[i];</pre>

  <pre><span class="lnum">  13:  </span>            results += <span class="str">&quot;Matches[&quot;</span> + i.ToString() + <span class="str">&quot;]&quot;</span>;</pre>

  <pre><span class="lnum">  14:  </span>            results += <span class="str">&quot;\n\r\n\r&quot;</span>;</pre>

  <pre><span class="lnum">  15:  </span>            <span class="kwrd">for</span> (<span class="kwrd">int</span> j = 0; j &lt; m.Groups.Count; ++j)</pre>

  <pre><span class="lnum">  16:  </span>            {</pre>

  <pre><span class="lnum">  17:  </span>                Group g = m.Groups[j];</pre>

  <pre><span class="lnum">  18:  </span>&#160;</pre>

  <pre><span class="lnum">  19:  </span>                results += <span class="str">&quot;    .Groups[&quot;</span>;</pre>

  <pre><span class="lnum">  20:  </span>                <span class="kwrd">string</span> name = r.GroupNameFromNumber(j);</pre>

  <pre><span class="lnum">  21:  </span>&#160;</pre>

  <pre><span class="lnum">  22:  </span>                <span class="kwrd">if</span> (name == j.ToString())</pre>

  <pre><span class="lnum">  23:  </span>                    results += name;</pre>

  <pre><span class="lnum">  24:  </span>                <span class="kwrd">else</span></pre>

  <pre><span class="lnum">  25:  </span>                    results += <span class="str">&quot;\&quot;&quot;</span> + name + <span class="str">&quot;\&quot;&quot;</span>;</pre>

  <pre><span class="lnum">  26:  </span>                results += <span class="str">&quot;]\n\r\n\r&quot;</span>;</pre>

  <pre><span class="lnum">  27:  </span>&#160;</pre>

  <pre><span class="lnum">  28:  </span>                <span class="kwrd">for</span> (<span class="kwrd">int</span> k=0; k &lt; g.Captures.Count; ++k) </pre>

  <pre><span class="lnum">  29:  </span>                {</pre>

  <pre><span class="lnum">  30:  </span>                    Capture c = g.Captures[k];</pre>

  <pre><span class="lnum">  31:  </span>                    results += <span class="str">&quot;        .Captures[&quot;</span>+k+<span class="str">&quot;]=\&quot;&quot;</span> + c.Value + <span class="str">&quot;\&quot;\n\r\n\r&quot;</span>;</pre>

  <pre><span class="lnum">  32:  </span>                }</pre>

  <pre><span class="lnum">  33:  </span>                </pre>

  <pre><span class="lnum">  34:  </span>            }</pre>

  <pre><span class="lnum">  35:  </span>            </pre>

  <pre><span class="lnum">  36:  </span>        }</pre>

  <pre><span class="lnum">  37:  </span>        Results.Text = results;</pre>

  <pre><span class="lnum">  38:  </span>        RegularExpression.ForeColor = Color.Black;</pre>

  <pre><span class="lnum">  39:  </span>    }</pre>

  <pre><span class="lnum">  40:  </span>    <span class="kwrd">catch</span> (System.Exception e)</pre>

  <pre><span class="lnum">  41:  </span>    {</pre>

  <pre><span class="lnum">  42:  </span>        Results.Text = e.Message;</pre>

  <pre><span class="lnum">  43:  </span>        RegularExpression.ForeColor = Color.Red;</pre>

  <pre><span class="lnum">  44:  </span>    }</pre>

  <pre><span class="lnum">  45:  </span>}</pre>
</div>
<style type="text/css">.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; } </style>

<p><strong></strong>&#160;</p>

<p>The try-catch block (lines 3-44) is used to catch errors that occur during the application of the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a>. If an error is detected, the error message is shown in the results pane (lines 40-44) and the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> text is colored red.</p>

<p>Normally the code enters the try block at line 3. The string called <strong><em>results</em></strong> (line 6) is used to accumulate the text that will go into the results panel. Accumulating the results into a string seems to be more performant than accumulating them directly into <strong><em>Results.Text</em></strong>, probably because each change to <strong><em>Results.Text</em></strong> forces the <a title="System.Windows.Forms.TextBox" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsTextBoxClassTopic.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWindowsFormsTextBoxClassTopic.asp">TextBox</a> to redo its text layout computations. In this code, all the changes are accumulated into <strong><em>results</em></strong> and only at the end is the string copied into <em><strong>Results.Text</strong></em>.</p>

<p>The <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> is applied to the sample text in line 8 and a <a title="System.Text.RegularExpressions.MatchCollection" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.matchcollection.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.matchcollection.aspx">MatchCollection</a> returns the set of <a title="System.Text.RegularExpressions.Match" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx">Matches</a> in line 9. The nested for-loops in lines 10-36, 15-34, 28-32 walk through the <a title="System.Text.RegularExpressions.Match" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx">Match</a>/<a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Group</a>/<a title="System.Text.RegularExpressions.Capture" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx">Capture</a> hierarchy, converting it into human readable text which is accumulated in the <strong><em>results</em></strong> string. The <strong><em>results</em></strong> string is used to set the Text property of the results region on line 37. The only part that is not completely straight forward is the if statement on lines 22-25 which checks to see if the <a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Group</a> is named in order to determine whether to output a numerical or string indexer.</p>

<p>To understand how to actually extract matched values from an input string, it helps to understand the hierarchical <a title="System.Text.RegularExpressions.Match" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx">Match</a>/<a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Group</a>/<a title="System.Text.RegularExpressions.Capture" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx">Capture</a> data structure created by the <a title="System.Text.RegularExpressions.Regex class" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.regex.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.regex.aspx">Regex</a> in line 9. The root of the hierarchy is a <a title="System.Text.RegularExpressions.MatchCollection" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.matchcollection.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.matchcollection.aspx">MatchCollection</a> with one <a title="System.Text.RegularExpressions.Match" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx">Match</a> for each portion of the input string that matches the entire <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> string (line 9). Each <a title="System.Text.RegularExpressions.Match" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx">Match</a> contains one or more <a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Groups</a> (line 15). The first <a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Group</a> always corresponds to the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> in its entirety. Subsequent <a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Groups</a> correspond to <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">grouping constructs</a> within the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a>. A <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">grouping construct</a> is just a parenthesized sub-expression of a <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a>. <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">Grouping constructs</a> are sometimes used to capture the input text matching specific portions of a larger match. As an example, one could use a <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">grouping construct</a> to capture the area code from a larger expression that matches phone numbers:</p>

<blockquote>
  <p>(\d\d\d)-\d\d\d-\d\d\d\d</p>
</blockquote>

<p><a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">Grouping constructs</a> can also used when applying <a title="Quantifiers" href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx">quantifiers</a> in <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a>. As an example, one could match the string &quot;abcabcabc&quot; using a <a title="Quantifiers" href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx">quantifier</a> in combination with an expression that matches &quot;abc&quot;:</p>

<blockquote>
  <p>(abc){3}</p>
</blockquote>

<p>Each <a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Group</a> contains one or more <a title="System.Text.RegularExpressions.Capture" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx">Captures</a>, each of which corresponds to one of the allowed matches for an expression with a <a title="Quantifiers" href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx">quantifier</a>. As an example, when the expression</p>

<blockquote>
  <p>(dog|cat){3}</p>
</blockquote>

<p>is applied to the string &quot;dogdogcat&quot;, the resulting subexpression group will contain three <a title="System.Text.RegularExpressions.Capture" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx">Captures</a>, one each for &quot;dog&quot;, &quot;dog&quot;, and &quot;cat&quot; (see Figure 2). </p>

<p><a href="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image03.png" mce_href="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image03.png"><img src="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image0_thumb3.png" width="523" height="449" mce_src="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image0_thumb3.png" /></a> </p>

<p><strong>Figure 2. An subexpression with a quantifier maps to a group with multiple captures.</strong></p>

<p>As you can see, the Interactive Regular Expression Evaluator makes it easy to quickly examine the <a title="System.Text.RegularExpressions.Match" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx">Match</a>/<a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Group</a>/<a title="System.Text.RegularExpressions.Capture" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx">Capture</a> hierarchy for a particular combination of sample data and <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a>. I encourage you to follow along in the evaluator as you read through the next section which describes the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> that extracts useful values from the <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> data.</p>

<h3><strong>Building An Expression to Extract Sensor ID, Temperature, and Humidity</strong></h3>

<p>In the <a title="Home Automation Part 2 – Making Basic Measurements" href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx" mce_href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx">previous installment</a> we saw that a &quot;D&quot; command to the <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> would trigger a response that looks something like</p>

<pre class="csharpcode">2621D453000000F1 19,17.81,64.00,44
262FD453000000E2 19,18.12,64.56,43
EOD
</pre>

<p>Basically, each sensor returns a line of data of the form</p>

<blockquote>
  <p>xxxxxxxxxxxxxxxx ss,ccc.cc,fff.ff,hhh</p>
</blockquote>

<p>where </p>

<ul>
  <li><em>xxxxxxxxxxxxxxxx</em> is a 16 digit hexadecimal sensor ID </li>

  <li><em>ss</em> is the sensor type </li>

  <li><em>ccc.cc</em> is the temperature in degrees Celsius </li>

  <li><em>fff.ff</em> is the temperature in degrees Fahrenheit </li>

  <li><em>hhh</em> is the humidity</li>
</ul>

<p>After the last sensor, the result set is terminated by a line containing the string &quot;EOD&quot;. </p>

<p><strong>Matching the Sensor ID.</strong> Let’s start by building the portion of the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> that extracts the sensor ID into a named <a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Group</a> called “Id”. We will start by using the [] <a title="Character Class" href="https://msdn2.microsoft.com/en-us/library/20bw873z.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/20bw873z.aspx">character class</a> construct to match a single hexadecimal digit. The []-construct will match a single instance of any character that appears between the square brackets. As an example, [abc] would match ‘a’, ‘b’, or ‘c’. We can match a single hexadecimal digit with </p>

<blockquote>
  <p>[0123456789ABCDEF]</p>
</blockquote>

<p>The – operator allows us to specify ranges of Unicode characters in a <a title="Character Class" href="https://msdn2.microsoft.com/en-us/library/20bw873z.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/20bw873z.aspx">character class</a>, leading to more compact <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expressions</a>. As an example, [a-z] will match any lower case English letter. Using – , we can write a the following equivalent but more compact expression to match a single hexadecimal digit: </p>

<blockquote>
  <p>[0-9A-F]</p>
</blockquote>

<p>Sensor IDs consist of a sequence of 16 hexadecimal digits. We can use the {} <a title="Quantifiers" href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx">quantifier</a> construct to specify the number of adjacent digits to match. The {} construct modifies a regular expression to match multiple copies of its original matching input. As an example, the regular expression a{3} will match “aaa” and is equivalent to the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expressions</a> aa{2} and aaa. We can match exactly 16 hexadecimal digits with </p>

<blockquote>
  <p>[0-9A-F]{16}</p>
</blockquote>

<p>Now that we can match the sensor ID, we’d like to actually extract it from the input string. I use a <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">parenthesized subexpression</a> to put the sensor ID into a match <a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Group</a>: </p>

<blockquote>
  <p>([0-9A-F]{16})</p>
</blockquote>

<p>Figure 3 shows the match/group/capture hierarchy for this expression when applied to sample data from the <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a>. Matches[0].Groups[0] is the match for the entire <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a>. Matches[0].Groups[1] is the match for the <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">parenthesized subexpression</a>. Since the entire <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> is parenthesized, the two <a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Groups</a> correspond to the same matched substring. </p>

<p><a href="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image05.png" mce_href="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image05.png"><img src="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image0_thumb5.png" width="523" height="449" mce_src="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image0_thumb5.png" /></a></p>

<p><strong>Figure 3. This regular expression extracts the first sensor ID.</strong></p>

<p>Accessing the extracted sensor ID from code is simple: </p>

<pre class="csharpcode">System.Console.WriteLine(Matches[0].Groups[1].Captures[0].Value);
</pre>

<p>This code is somewhat brittle because it assumes that the sensor ID will always be in the second <a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Group</a>. Any change to the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> that introduces another <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">subexpression</a> before the sensor ID <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">subexpression</a> will break the code. We can fix this problem by assigning a name to the sensor ID <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">subexpression</a> using the ?&lt;&gt; construct. Here’s an expression that captures a sequence of 16 hexadecimal digits into a <a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Group</a> called “Id”: </p>

<blockquote>
  <p>(?&lt;Id&gt;[0-9A-F]{16})</p>
</blockquote>

<p>The code to access the sensor ID now becomes: </p>

<pre class="csharpcode">System.Console.WriteLine(Matches[0].Groups[&quot;Id&quot;].Captures[0].Value);
</pre>

<p>This code is better because it does not depend on the position of the sensor ID <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">subexpression</a> relative to other <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">subexpressions</a>. Now let's extend the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> to grab the temperature.</p>

<p><strong>Matching the Temperature and Humidity.</strong> I want to use Fahrenheit temperatures so after matching the sensor ID, my expression will need to skip over the sensor type and Celsius temperature before matching the Fahrenheit temperature. Skipping over the sensor type is easy - we just need to skip over a space, a two digit sensor type, and a comma. This can be done by appending</p>

<blockquote>
  <p>\s\d\d,</p>
</blockquote>

<p>to the end of the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> for the sensor ID. In this expression, \s denotes a <a title="Character Class" href="https://msdn2.microsoft.com/en-us/library/20bw873z.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/20bw873z.aspx">character class</a> that matches any whitespace and \d denotes a <a title="Character Class" href="https://msdn2.microsoft.com/en-us/library/20bw873z.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/20bw873z.aspx">character class</a> that matches any decimal digit in the range 0 to 9.</p>

<p>The Celsius temperature is a bit more complex because when the temperature is below freezing, it starts with a minus sign. After that there are 1-3 decimal digits followed by a decimal point followed two more decimal digits.</p>

<p>We can use the ? <a title="Quantifiers" href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx">quantifier</a> to handle the minus sign. ? modifies an expression to match 0 or 1 instances, so the expression -? matches the minus sign when its cold but doesn't complain when its hot. </p>

<p>Earlier I used the {16} <a title="Quantifiers" href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx">quantifier</a> to match exactly 16 hexadecimal digits in the sensor ID. Another form of the {} <a title="Quantifiers" href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx">quantifier</a> allows you to specify an upper and lower bound for the number of matches. A <a title="Quantifiers" href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx">quantifier</a> of the form {x,y} will match at least x, but no more than y instances. Putting it all together, we can match the Celsius temperature with</p>

<blockquote>
  <p>-?\d{1,3}\.\d{2}</p>
</blockquote>

<p>In this expression, the period is preceded by a backslash to indicate a match to a period. Without the backslash, period corresponds to a <a title="Character Class" href="https://msdn2.microsoft.com/en-us/library/20bw873z.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/20bw873z.aspx">character class</a> that matches any character. </p>

<p>We can use the identical expression to match the Fahrenheit temperature, but we'll add a named <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">subexpression</a> to allow us to capture the value into a group:</p>

<blockquote>
  <p>(?&lt;Temp&gt;-?\d{1,3}\.\d{2})</p>
</blockquote>

<p>After this, matching the humidity is a snap - it is just a pair of decimal digits. There is one catch, though. The sensor network could contain sensors that only report temperature. In this case, the humidity value and the comma that separates it from the temperature would not appear in the <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> data. We can use the ? <a title="Quantifiers" href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx">quantifier</a> to make the entire humidity expression optional:</p>

<blockquote>
  <p>(,(?&lt;Humidity&gt;\d{2}))?</p>
</blockquote>

<p>This expression is less efficient than it could be because it captures the humidity value twice, once with the comma and once without. The reason is that I had to add a second <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">parenthesized subexpression</a> in order to make the ? <a title="Quantifiers" href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/3206d374.aspx">quantifier</a> apply to the sequence containing the comma <em>and</em> the humidity. We can improve the expression by using ?: to denote a <a title="Grouping Constructs" href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/bs2twtah.aspx">non-capturing group</a>:</p>

<blockquote>
  <p>(?:,(?&lt;Humidity&gt;\d{2}))?</p>
</blockquote>

<p>Now we're ready to put it all together and write one giant expression to grab the sensor IDs, temperatures, and humidity values from the <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> data. We do this by appending the following expression fragments:</p>

<ul>
  <li><strong>Match sensor ID:</strong> (?&lt;Id&gt;[0-9A-F]{16}) </li>

  <li><strong>Skip space, sensor type, and comma:</strong> \s\d\d, </li>

  <li><strong>Skip Celsius temperature and comma:</strong> -?\d{1,3}\.\d{2}, </li>

  <li><strong>Match Fahrenheit temperature:</strong> (?&lt;Temp&gt;-?\d{1,3}\.\d{2}) </li>

  <li><strong>Match optional humidity:</strong> (?:,(?&lt;Humidity&gt;\d{2}))?</li>
</ul>

<p>Here's the final, almost incomprehensible expression:</p>

<blockquote>
  <p>(?&lt;Id&gt;[0-9A-F]{16})\s\d\d,-?\d{1,3}\.\d{2},(?&lt;Temp&gt;-?\d{1,3}\.\d{2})(?:,(?&lt;Humidity&gt;\d{2}))?</p>
</blockquote>

<p>Figure 4 shows the expression in action.</p>

<p><a href="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image09.png" mce_href="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image09.png"><img src="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image0_thumb9.png" width="523" height="553" mce_src="https://hopcroft.members.winisp.net/images/HomeAutomationPart3UsingRegularExpressio_BA4B/image0_thumb9.png" /></a> </p>

<p><strong>Figure 4. The final regular expression applied to real <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> data.</strong></p>

<p>Now that we have the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a>, lets modify the <a title="Home Automation Part 2 – Making Basic Measurements" href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx" mce_href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx">Super-Simple Serial Console</a> from my <a title="Home Automation Part 2 – Making Basic Measurements" href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx" mce_href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx">previous installment</a> to poll the sensor network and print out the sensor IDs, temperatures, and humidity levels.</p>

<p><strong>Polling the Sensor Network.</strong> The goal here is to write a small console application that initializes the sensor network and then every 5 seconds, takes a set of readings and prints them to the console. This application will form the heart of a data logging service that we will implement in a future installment.</p>

<p>It turns out that <a title="System.IO.Ports.SerialPort" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.aspx">System.IO.Ports.SerialPort</a> has a feature that allows us to greatly simplify the code from the <a title="Home Automation Part 2 – Making Basic Measurements" href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx" mce_href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx">Super-Simple Serial Console</a>. Recall that the <a title="Home Automation Part 2 – Making Basic Measurements" href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx" mce_href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx">Super-Simple Serial Console</a> needed a bit of multiple-thread coordination to avoid printing the prompt before the <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> had finished responding. Since our new application only runs the <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> &quot;D&quot; command, we can take advantage of the fact that all of the <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> responses will be terminated by the characters &quot;EOD&quot;, allowing us to use the serial port's <a title="SerialPort.ReadTo method" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.readto.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.readto.aspx">ReadTo()</a> method.&#160; </p>

<p><a title="SerialPort.ReadTo method" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.readto.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.readto.aspx">ReadTo()</a> takes a single string argument and blocks until this string appears in the serial port's input buffer or a read timeout limit has been exceeded. When <a title="SerialPort.ReadTo method" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.readto.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.readto.aspx">ReadTo()</a> detects the termination string, it returns the string of characters received up until the termination string. The termination string itself is not returned, but it is removed from the serial port's input buffer. Listing 2 shows the sensor reading application.</p>

<p><strong>Listing 2. This application reads the sensor data and prints it to the console.</strong></p>

<div class="csharpcode">
  <pre><span class="lnum">   1:  </span><span class="kwrd">using</span> System;</pre>

  <pre><span class="lnum">   2:  </span><span class="kwrd">using</span> System.IO.Ports;</pre>

  <pre><span class="lnum">   3:  </span><span class="kwrd">using</span> System.Text.RegularExpressions;</pre>

  <pre><span class="lnum">   4:  </span><span class="kwrd">using</span> System.Threading;</pre>

  <pre><span class="lnum">   5:  </span>&#160;</pre>

  <pre><span class="lnum">   6:  </span><span class="kwrd">namespace</span> SensorConsole</pre>

  <pre><span class="lnum">   7:  </span>{</pre>

  <pre><span class="lnum">   8:  </span>    <span class="rem">// SensorConsole reads from the sensor network every 5 seconds and prints the</span></pre>

  <pre><span class="lnum">   9:  </span>    <span class="rem">// sensor id, temperature, and humidity for each sensor.</span></pre>

  <pre><span class="lnum">  10:  </span>    <span class="kwrd">class</span> SensorConsole</pre>

  <pre><span class="lnum">  11:  </span>    {</pre>

  <pre><span class="lnum">  12:  </span>        <span class="kwrd">private</span> SerialPort port;</pre>

  <pre><span class="lnum">  13:  </span>&#160;</pre>

  <pre><span class="lnum">  14:  </span>        <span class="kwrd">public</span> <span class="kwrd">void</span> Run()</pre>

  <pre><span class="lnum">  15:  </span>        {</pre>

  <pre><span class="lnum">  16:  </span>            Console.WriteLine(<span class="str">&quot;Temperature and Humidity Logger&quot;</span>);</pre>

  <pre><span class="lnum">  17:  </span>            <span class="kwrd">try</span></pre>

  <pre><span class="lnum">  18:  </span>            {</pre>

  <pre><span class="lnum">  19:  </span>                Open();</pre>

  <pre><span class="lnum">  20:  </span>&#160;</pre>

  <pre><span class="lnum">  21:  </span>                Regex r = <span class="kwrd">new</span> Regex(<span class="str">@&quot;(?&lt;Id&gt;[0-9A-F]{16})\s\d\d,-?\d{1,3}\.\d{2},(?&lt;Temp&gt;-?\d{1,3}\.\d{2})(?:,(?&lt;Humidity&gt;\d{2}))?&quot;</span>);</pre>

  <pre><span class="lnum">  22:  </span>&#160;</pre>

  <pre><span class="lnum">  23:  </span>                <span class="kwrd">while</span> (<span class="kwrd">true</span>)</pre>

  <pre><span class="lnum">  24:  </span>                {</pre>

  <pre><span class="lnum">  25:  </span>                    <span class="kwrd">try</span></pre>

  <pre><span class="lnum">  26:  </span>                    {</pre>

  <pre><span class="lnum">  27:  </span>                        port.Write(<span class="str">&quot;D&quot;</span>);</pre>

  <pre><span class="lnum">  28:  </span>                        <span class="kwrd">string</span> s = port.ReadTo(<span class="str">&quot;EOD&quot;</span>);</pre>

  <pre><span class="lnum">  29:  </span>&#160;</pre>

  <pre><span class="lnum">  30:  </span>                        MatchCollection matches = r.Matches(s);</pre>

  <pre><span class="lnum">  31:  </span>                        <span class="kwrd">foreach</span> (Match m <span class="kwrd">in</span> matches)</pre>

  <pre><span class="lnum">  32:  </span>                        {</pre>

  <pre><span class="lnum">  33:  </span>                            Int64 id = Int64.Parse(m.Groups[<span class="str">&quot;Id&quot;</span>].Value, System.Globalization.NumberStyles.HexNumber);</pre>

  <pre><span class="lnum">  34:  </span>                            <span class="kwrd">float</span> temp = <span class="kwrd">float</span>.Parse(m.Groups[<span class="str">&quot;Temp&quot;</span>].Value);</pre>

  <pre><span class="lnum">  35:  </span>                            <span class="kwrd">int</span> humidity = <span class="kwrd">int</span>.Parse(m.Groups[<span class="str">&quot;Humidity&quot;</span>].Value);</pre>

  <pre><span class="lnum">  36:  </span>                            Console.WriteLine(<span class="str">&quot;{0:X}: {1} degrees F and {2}% humidity&quot;</span>, id, temp, humidity);</pre>

  <pre><span class="lnum">  37:  </span>                        }</pre>

  <pre><span class="lnum">  38:  </span>                        Console.WriteLine();</pre>

  <pre><span class="lnum">  39:  </span>                    }</pre>

  <pre><span class="lnum">  40:  </span>                    <span class="kwrd">catch</span> (System.Exception e)</pre>

  <pre><span class="lnum">  41:  </span>                    {</pre>

  <pre><span class="lnum">  42:  </span>                        <span class="kwrd">if</span> (e <span class="kwrd">is</span> System.TimeoutException)</pre>

  <pre><span class="lnum">  43:  </span>                        {</pre>

  <pre><span class="lnum">  44:  </span>                            Console.WriteLine(<span class="str">&quot;Error: timeout reading sensor data.&quot;</span>);</pre>

  <pre><span class="lnum">  45:  </span>                        }</pre>

  <pre><span class="lnum">  46:  </span>                        <span class="kwrd">else</span></pre>

  <pre><span class="lnum">  47:  </span>                            <span class="kwrd">throw</span> e;</pre>

  <pre><span class="lnum">  48:  </span>                    }</pre>

  <pre><span class="lnum">  49:  </span>&#160;</pre>

  <pre><span class="lnum">  50:  </span>                    <span class="rem">// Wait 5s between sensor readings.</span></pre>

  <pre><span class="lnum">  51:  </span>                    Thread.Sleep(5000);</pre>

  <pre><span class="lnum">  52:  </span>                }</pre>

  <pre><span class="lnum">  53:  </span>            }</pre>

  <pre><span class="lnum">  54:  </span>            <span class="kwrd">finally</span></pre>

  <pre><span class="lnum">  55:  </span>            {</pre>

  <pre><span class="lnum">  56:  </span>                <span class="kwrd">if</span> (port != <span class="kwrd">null</span> &amp;&amp; port.IsOpen)</pre>

  <pre><span class="lnum">  57:  </span>                    port.Close();</pre>

  <pre><span class="lnum">  58:  </span>            }</pre>

  <pre><span class="lnum">  59:  </span>        }</pre>

  <pre><span class="lnum">  60:  </span>&#160;</pre>

  <pre><span class="lnum">  61:  </span>        <span class="kwrd">void</span> Open()</pre>

  <pre><span class="lnum">  62:  </span>        {</pre>

  <pre><span class="lnum">  63:  </span>            port = <span class="kwrd">new</span> SerialPort(<span class="str">&quot;COM1&quot;</span>, 9600, Parity.None, 8, StopBits.One);</pre>

  <pre><span class="lnum">  64:  </span>&#160;</pre>

  <pre><span class="lnum">  65:  </span>            <span class="rem">// The iButton Link45 needs DTR and RTS enabled.</span></pre>

  <pre><span class="lnum">  66:  </span>            port.DtrEnable = <span class="kwrd">true</span>;</pre>

  <pre><span class="lnum">  67:  </span>            port.RtsEnable = <span class="kwrd">true</span>;</pre>

  <pre><span class="lnum">  68:  </span>&#160;</pre>

  <pre><span class="lnum">  69:  </span>            <span class="rem">// Bump up the read timeout from the default 500ms to ensure time for </span></pre>

  <pre><span class="lnum">  70:  </span>            <span class="rem">// reporting from large sensor networks.</span></pre>

  <pre><span class="lnum">  71:  </span>            port.ReadTimeout = 5000;</pre>

  <pre><span class="lnum">  72:  </span>&#160;</pre>

  <pre><span class="lnum">  73:  </span>            <span class="rem">// The serial port is now configured and ready to be opened.</span></pre>

  <pre><span class="lnum">  74:  </span>            port.Open();</pre>

  <pre><span class="lnum">  75:  </span>&#160;</pre>

  <pre><span class="lnum">  76:  </span>            <span class="rem">// Shock the Link45 to life by sending a break.</span></pre>

  <pre><span class="lnum">  77:  </span>            port.BreakState = <span class="kwrd">true</span>;</pre>

  <pre><span class="lnum">  78:  </span>            port.BreakState = <span class="kwrd">false</span>;</pre>

  <pre><span class="lnum">  79:  </span>        }</pre>

  <pre><span class="lnum">  80:  </span>&#160;</pre>

  <pre><span class="lnum">  81:  </span>        <span class="kwrd">void</span> Close()</pre>

  <pre><span class="lnum">  82:  </span>        {</pre>

  <pre><span class="lnum">  83:  </span>            port.Close();</pre>

  <pre><span class="lnum">  84:  </span>        }</pre>

  <pre><span class="lnum">  85:  </span>    }</pre>

  <pre><span class="lnum">  86:  </span>&#160;</pre>

  <pre><span class="lnum">  87:  </span>    <span class="kwrd">class</span> Program</pre>

  <pre><span class="lnum">  88:  </span>    {</pre>

  <pre><span class="lnum">  89:  </span>        <span class="kwrd">static</span> <span class="kwrd">void</span> Main(<span class="kwrd">string</span>[] args)</pre>

  <pre><span class="lnum">  90:  </span>        {</pre>

  <pre><span class="lnum">  91:  </span>            SensorConsole sc = <span class="kwrd">new</span> SensorConsole();</pre>

  <pre><span class="lnum">  92:  </span>            sc.Run();</pre>

  <pre><span class="lnum">  93:  </span>        }</pre>

  <pre><span class="lnum">  94:  </span>    }</pre>

  <pre><span class="lnum">  95:  </span>}</pre>
</div>

<p>Let's walk through the code in execution order, starting at the entry point on line 89. <strong><em>Main()</em></strong> just creates a <strong><em>SensorConsole</em></strong> and invokes its <strong><em>Run()</em></strong> method. The body of the <strong><em>Run()</em></strong> method is protected by a try-finally block (line 17-58) that ensures the serial port is closed before returning from <strong><em>Run()</em></strong>. </p>

<p>The first order of business inside the try block is to call the <strong><em>Open()</em></strong> method (lines 61-79) which initializes the serial port. The <strong><em>Open()</em></strong> method is nearly the same as the one in the <a title="Home Automation Part 2 – Making Basic Measurements" href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx" mce_href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx">Super-Simple Serial Console</a>. The differences are that we no longer need to wire up the serial port's <a title="SerialPort.DataReceived Event" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx">DataReceived</a> event because we are using <a title="SerialPort.ReadTo method" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.readto.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.readto.aspx">ReadTo()</a> and we bumped up the serial port's <a title="SerialPort.ReadTimeout property" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.readtimeout.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.readtimeout.aspx">ReadTimeout</a> from 500ms to 5000ms to be on the safe side in case the <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> takes more than a half a second to return data from a large sensor network.</p>

<p>After returning from <strong><em>Open()</em></strong>, the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> is built using the <a title="System.Text.RegularExpressions.Regex class" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.regex.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.regex.aspx">Regex</a> class (line 21). Note the @-sign immediately before the <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> string. The @-sign indicates to the compiler that the following string should be treated literally with no special meaning for the backslashes. If I didn't use the @-sign, I would have had to escape each of the backslashes with &quot;\\&quot; which would have led to an even less comprehensible <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a>.</p>

<p>The main loop spans from line 23 to 52. Right inside the loop a try block (lines 25-48) is used to separate serial port timeout exceptions from other potential problems. As this code morphs into a more sophisticated always-on data logger, I will need to extend this error handling so that the logger stays up and running in the presence of intermittent communication or sensor failures.</p>

<p>Inside the try block, we issue a &quot;D&quot; command to the <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> on line 27 and then wait for a response on Line 28. Assuming we didn't get a timeout exception, control passes to line 30 where the our <a title=".NET Framework Regular Expressions" href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/hs600312.aspx">regular expression</a> is applied to the <a href="https://www.ibuttonlink.com/Link_Details.htm" mce_href="https://www.ibuttonlink.com/Link_Details.htm">Link45</a> data. The foreach loop on lines 31-37 walks over each of the <a title="System.Text.RegularExpressions.Match" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.match.aspx">Matches</a>, extracting the sensor ID, temperature, and humidity. Since the expression is designed to return a single <a title="System.Text.RegularExpressions.Capture" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.capture.aspx">Capture</a> per <a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Group</a>, I've used the shorthand of <strong><em>m.Groups[&quot;Id&quot;].Value</em></strong> instead of the more verbose <strong><em>m.Groups[&quot;Id&quot;].Captures[0].Value</em></strong>. The <a title="System.Text.RegularExpressions.Group" href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.text.regularexpressions.group.aspx">Group</a> values are returned as strings so I pass the ID, temperature, and humidity to <a title="Int64.Parse method" href="https://msdn2.microsoft.com/en-gb/library/3b6b4bx3.aspx" mce_href="https://msdn2.microsoft.com/en-gb/library/3b6b4bx3.aspx">Int64.Parse()</a>, <a title="Single.Parse method" href="https://msdn2.microsoft.com/en-us/library/2thct5cb.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/2thct5cb.aspx">float.Parse()</a>, and <a title="Int32.Parse method" href="https://msdn2.microsoft.com/en-us/library/system.int32.parse.aspx" mce_href="https://msdn2.microsoft.com/en-us/library/system.int32.parse.aspx">int.Parse()</a> in order to get the data into the correct types. After converting the strings, we print the values back out to the console (line 36) and head to the top of the foreach loop (line 31) to process the next sensor's results. When we run out of sensors, we print out a blank line (line 38), sleep for 5 seconds (line 51) and then head to the top of the while loop (line 23) to do it all over again.</p>

<p>We can now read the sensor network and extract useful fields like sensor ID, temperature, and humidity. Our next step will be to log the sensor values to a <a title="Microsoft SQL Server 2005 Home" href="https://www.microsoft.com/sql/default.mspx" mce_href="https://www.microsoft.com/sql/default.mspx">SQL database</a>. </p>

<p><strong>Next Installment: Logging sensor values to a database.</strong>&#160;</p>
<style type="text/css">.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; } </style><a href="https://www.dotnetkicks.com/kick/?url=https://blogs.msdn.com/mhop/archive/2007/01/07/home-automation-part-3-using-regular-expressions-to-parse-sensor-data.aspx"><img border="0" alt="kick it on DotNetKicks.com" src="https://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=https://blogs.msdn.com/mhop/archive/2007/01/07/home-automation-part-3-using-regular-expressions-to-parse-sensor-data.aspx" /></a>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Components.PostAttachments/00/01/43/31/09/RegExEvaluator.zip" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-01-43-31-09/RegExEvaluator.zip">RegExEvaluator.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Building a traffic signal with Christmas lights</title>
      <link>https://docs.microsoft.com/archive/blogs/mhop/building-a-traffic-signal-with-christmas-lights</link>
      <pubDate>Tue, 19 Dec 2006 03:12:00 GMT</pubDate>
      <dc:creator><![CDATA[mhop]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mhop/2006/12/19/building-a-traffic-signal-with-christmas-lights/</guid>
      <description><![CDATA[It started out as a simple project. My children had become interested in basic electrical circuits...]]></description>
      <content:encoded><![CDATA[<p>It started out as a simple project. My children had become interested in basic electrical circuits so&nbsp;I bought them some <a title="Wikipedia - LED" href="https://en.wikipedia.org/wiki/Led" target="_blank">LEDs</a>, batteries, wire, and <a title="Wikipedia Breadboard" href="https://en.wikipedia.org/wiki/Breadboard" target="_blank">solderless breadboard</a> to play around with. I soon found that these components weren't ideal for a number of reasons. While the solderless breadboard makes it easy to wire up circuits, it hides many of the electrical connections inside making it harder for children to grasp the concept of a circuit. In order to light up, the LEDs must be wired with the correct polarity and their uninsulated leads must not make a short. These factors combined to make it hard for the children to consistently build circuits that would light up.</p>
<p><strong>A simple idea.</strong> I had a moment of inspiration one evening while walking&nbsp;my dog through the neighborhood in the days leading up to Christmas. I realized that miniature Christmas lights actually only require a few volts to light up. A string of Christmas lights&nbsp;runs on&nbsp;120v, but the bulbs are wired in <a title="Wikipedia - Series and parallel circuits" href="https://en.wikipedia.org/wiki/Series_circuit" target="_blank">series</a>&nbsp;so an individual bulb needs only 2-3 volts, a safe amount that can be obtained through a pair of flashlight batteries. (you can find out everything you ever wanted to know about Christmas lights <a title="Christmas Lights and How to Fix Them" href="https://www.ciphersbyritter.com/RADELECT/LITES/XMSLITES.HTM" target="_blank">here</a>)</p>
<p>Christmas lights have a number of advantages over LEDs. They come in sockets with insulated wires already attached, they come in many colors, they all use the same voltage, and they don't care about polarity. Another benefit is cost. At most hardware stores you can purchase five replacement bulbs for about a dollar, but they don't come in sockets (see Figure 1).</p>
<p><br /><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/IMG_58111.jpg" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/IMG_5811_thumb1.jpg" width="640" height="480" /></a></p>
<p><strong>Figure 1.&nbsp;Five bulbs and&nbsp;no sockets for&nbsp;99&cent; at the local hardware store.</strong></p>
<p>A better deal is to purchase 100 bulbs and 100 sockets and 100 feet of wire&nbsp;for about three dollars (see Figure 2) and if you wait until the day after Christmas you can probably do even better.<a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/IMG_5811.jpg" atomicselection="true"></a></p>
<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/IMG_58125.jpg" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/IMG_5812_thumb5.jpg" width="640" height="480" /></a></p>
<p><strong>Figure 2. These bulbs cost about 3&cent; each and come in convenient pre-wired sockets.</strong></p>
<p>I ended up getting&nbsp;a few&nbsp;strings of lights along with a battery holder, some alligator clips, and a knife switch. After cutting a light out of the string I was able to make a simple circuit (see Figure 3)&nbsp;and I felt that it illustrated the concepts better than the LEDs and solderless breadboard. Everything in this circuit is visible and can be manipulated and arranged. I like how the knife switch really gets at the essence&nbsp;of closing a circuit.&nbsp;</p>
<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/IMG_58131.jpg" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/IMG_5813_thumb1.jpg" width="640" height="480" /></a></p>
<p><strong>Figure 3. This circuit is easy to understand because everything is visible.</strong></p>
<p>To be safe, I cut off both 120v plugs from the string of lights and then gave the lights&nbsp;to my kids along with a wire cutter/stripper&nbsp;and the batteries, alligator clamps, and knife switches. They quickly made simple circuits and then proceeded to wire up lights for their <a title="LEGO.com The Official Web Site of LEGO (r) products!" href="https://www.lego.com" target="_blank">Lego</a> creations and dioramas. I probably should have stopped here.</p>
<p><strong>A simple idea&nbsp;grows into&nbsp;a bigger project.</strong> As I watched the kids&nbsp;play with the lights I got the idea to make them a stoplight. I&nbsp;knew it would be too complex for them to wire up by themselves, but I figured they could make a nice cardboard box for it and put it to good use. I decided to use a 2-pole 6-throw rotary switch from <a title="RadioShack.com" href="https://www.radioshack.com" target="_blank">Radio Shack</a> to control 12 lamps. This would allow green, yellow, and red lamps for roads coming from 4 directions. Before getting out the soldering iron, I wrote down the&nbsp;a simple&nbsp;state table for the 6 positions of the rotary switch (see table 1). After writing&nbsp;down the state table, I realized that a four-position switch would have worked better since the light cycles through four states before repeating. I&nbsp;only had a six-position switch so I went with the circuit&nbsp;in figure 4.</p>
<p><strong>Table 1.&nbsp;State diagram for 2 roads crossing.&nbsp;</strong></p>
<table border="solid black 1" border-collapse="true">
<tbody>
<tr>
<td>Position</td>
<td>North/South Lamps</td>
<td>East/West Lamps</td>
</tr>
<tr>
<td>1</td>
<td>Green</td>
<td>Red</td>
</tr>
<tr>
<td>2</td>
<td>Yellow</td>
<td>Red</td>
</tr>
<tr>
<td>3</td>
<td>Red</td>
<td>Green</td>
</tr>
<tr>
<td>4</td>
<td>Red</td>
<td>Yellow</td>
</tr>
<tr>
<td>5</td>
<td>Green</td>
<td>Red</td>
</tr>
<tr>
<td>6</td>
<td>Yellow</td>
<td>Red</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/image01.png" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/image0_thumb1.png" width="738" height="645" /></a></p>
<p><strong>Figure 4. Circuit for 12 lights on a 6-position rotary switch.</strong></p>
<p>The circuit looks pretty simple, but it actually took me a while to build. The time consuming parts were scavenging and testing 12 lamps (figure 5), and soldering in close quarters on the rotary switch (figure 6).</p>
<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/IMG_58211.jpg" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/IMG_5821_thumb1.jpg" width="640" height="480" /></a></p>
<p><strong>Figure 5. A stoplight seems pretty simple, but it actually has 12 lamps inside.</strong></p>
<p><strong></strong>&nbsp;</p>
<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/IMG_58321.jpg" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/IMG_5832_thumb1.jpg" width="360" height="480" /></a></p>
<p><strong>Figure 6. Wiring the rotary switch was tricky.</strong></p>
<p>By the time I was done, I was really glad that I didn't attempt&nbsp;this project with the kids. They would have become bored long before the first solder melted. Figure 7 shows the completed circuit. I taped the bulbs to a board to help keep the wires under control and I made a long wire harness between the switch and the bulbs to simplify mounting in whatever enclosure the kids decide to invent.</p>
<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/IMG_58301.jpg" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/IMG_5830_thumb1.jpg" width="640" height="480" /></a></p>
<p><strong>Figure 7. What started as a simple project got complex.</strong></p>
<p>Overall, I was fairly satisfied with the stoplight, but am already making plans for a better one. It turned out that the rotary switch presented a number of challenges. One was that is was very hard for the kids to turn - they just couldn't get a tight enough grip on the shaft. I can fix this by putting a knob on the switch. The other problem is that the switch has a stop after position 6. I would have preferred a switch that could advance from position 6 back to position 1. I thought about cutting off the metal stop inside the switch, but decided against it because of the risk of breaking the switch that took so long to wire up.</p>
<p><strong>This may be getting out of hand. </strong>If I make another stoplight, I am going to place an emphasis on ease of assembly. I will probably use LEDs soldered directly onto a prototyping board as shown in figure 8.&nbsp;Instead of a complicated wiring harness, I'll&nbsp;use 8-conductor ribbon wire with a single inline plug.</p>
<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/image03.png" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/BuildingatrafficsignalwithChristmaslight_12138/image0_thumb3.png" width="723" height="581" /></a></p>
<p><strong>Figure 8. An easier-to-assemble design.</strong></p>
<p>I'll also replace the rotary switch with a simple sequencing circuit or perhaps a micro-controller such as a <a title="Basic Stamps" href="https://www.parallax.com/html_pages/products/basicstamps/basic_stamps.asp" target="_blank">Basic Stamp</a>. I like the micro-controller idea because I'd get to write software for features like flashing red, sequenced lights, and even pressure sensors. If I do this I'm sure you will read about it here.</p>
<p>Have a wonderful holiday and a happy New Year.</p>
<p>-Mike</p>]]></content:encoded>
    </item>
    <item>
      <title>Save the date for PDC '07</title>
      <link>https://docs.microsoft.com/archive/blogs/mhop/save-the-date-for-pdc-07</link>
      <pubDate>Thu, 14 Dec 2006 02:52:33 GMT</pubDate>
      <dc:creator><![CDATA[mhop]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mhop/2006/12/14/save-the-date-for-pdc-07/</guid>
      <description><![CDATA[Microsoft has just announced that the next Professional Developers Conference (PDC) will be October...]]></description>
      <content:encoded><![CDATA[<p>Microsoft has just announced that the next <a title="Professional Developers Conference" href="https://msdn.microsoft.com/events/pdc/">Professional Developers Conference</a> (PDC) will be October 2-5, 2007 in Los Angeles, with two days of pre-conference on September 30 and October 1. The last two PDCs were fantastic and this one is likely to be just as exciting and informative. You can find more information <a title="Professional Developers Conference" href="https://msdn.microsoft.com/events/pdc/">here</a>.</p> <p>Hope this helps.</p> <p>-Mike</p>]]></content:encoded>
    </item>
    <item>
      <title>Implicit and Explicit Interface Implementations</title>
      <link>https://docs.microsoft.com/archive/blogs/mhop/implicit-and-explicit-interface-implementations</link>
      <pubDate>Wed, 13 Dec 2006 02:59:13 GMT</pubDate>
      <dc:creator><![CDATA[mhop]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mhop/2006/12/13/implicit-and-explicit-interface-implementations/</guid>
      <description><![CDATA[As I was putting together a post on IEnumerable&nbsp;and IEnumerator&nbsp;I was reminded of the...]]></description>
      <content:encoded><![CDATA[<p>As I was putting together a post on <a title="IEnumerable Interface" href="https://msdn2.microsoft.com/en-us/library/system.collections.ienumerable.aspx">IEnumerable</a>&nbsp;and <a title="IEnumerator Interface" href="https://msdn2.microsoft.com/en-us/library/system.collections.ienumerator.aspx">IEnumerator</a>&nbsp;I was reminded of the subtleties of implicit and explicit interface implementations. C# does not support multiple inheritance, but a class has the option of implementing one or more interfaces. One challenge with interfaces is that they may include methods that have the same signatures as existing class members or members of other interfaces. Explicit interface implementations can be used to disambiguate class and interface methods that would otherwise conflict. Explicit interfaces can also be used to hide the details of an interface that the class developer considers private.</p> <p><strong>Disambiguating Methods</strong></p> <p>Let's look at an example of method disambiguation. In Listing 1 we have started to write a class called <strong>C</strong> that implements interfaces <strong>I1</strong> and <strong>I2</strong>, each of which defines a method <strong>A()</strong>.</p> <p><strong>Listing 1. Class C implements interfaces I1 and I2.</strong></p><pre class="csharpcode"><span class="kwrd">interface</span> I1
{
    <span class="kwrd">void</span> A();
}

<span class="kwrd">interface</span> I2
{
    <span class="kwrd">void</span> A();
}

<span class="kwrd">class</span> C : I1, I2
{
    <span class="kwrd">public</span> <span class="kwrd">void</span> A()
    {
        Console.WriteLine(<span class="str">"C.A()"</span>);
    }
}
</pre>
<style type="text/css">.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; }
</style>

<p>In this case, <strong>A()</strong> is a public class member that <em>implicitly</em> implements a member of&nbsp;<em>both</em> interfaces. <strong>A()</strong> can be invoked through either interface or through the class itself&nbsp;as follows:</p>
<p><strong>Listing 2. A() can be invoked from I1, I2, or C.</strong></p><pre class="csharpcode">C c = <span class="kwrd">new</span> C();
I1 i1 = (I1)c;
I2 i2 = (I2)c;

i1.A();
i2.A();
c.A();</pre>
<p>The output from this code is</p><pre class="csharpcode">C.A()
C.A()
C.A()</pre>
<p>This works fine if you want <strong>A()</strong> to do the same thing in both interfaces. In most cases, however, methods in different interfaces have distinct purposes requiring wholly different implementations. This is where explicit interface implementations come in handy. To explicitly implement an interface member, just use its fully qualified name in the declaration. A fully qualified interface name takes the form</p>
<blockquote>
<p>InterfaceName.MemberName</p></blockquote>
<p>In Listing 3 we add an explicit implementation of <strong>I1</strong>'s <strong>A()</strong> method.</p>
<p><strong>Listing 3. Class C explicitly implements I1.A().</strong></p><pre class="csharpcode"><span class="kwrd">class</span> C : I1, I2
{
    <span class="kwrd">public</span> <span class="kwrd">void</span> A()
    {
        Console.WriteLine(<span class="str">"C.A()"</span>);
    }

    <span class="kwrd">void</span> I1.A()
    {
        Console.WriteLine(<span class="str">"I1.A()"</span>);
    }
}</pre>
<p>Now when we run the statements from Listing 2 we get</p><pre class="csharpcode">I1.A()
C.A()
C.A()</pre>
<p>When an interface method is explicitly implemented, it is no longer visible as a public member of the class. The only way to access it is through the&nbsp;interface. As an example, suppose we deleted the implicit implementation of <strong>A()</strong> as shown in Listing 4:</p>
<p><strong>Listing 4. Class C does not implicitly implement A()</strong></p><pre class="csharpcode"><span class="kwrd">class</span> C : I1, I2
{
    <span class="kwrd">void</span> I1.A()
    {
        Console.WriteLine(<span class="str">"I2.A()"</span>);
    }
}
</pre>
<p>In this case we would get a compile error saying that <strong>C</strong> fails to implement <strong>I2.A()</strong>. We could fix this error by changing the first line to</p><pre class="csharpcode"><span class="kwrd">class</span> C : I1</pre>
<p>but we'd get another compile error when trying to invoke <strong>A()</strong> as a member of <strong>C</strong>:</p><pre class="csharpcode">C c = <span class="kwrd">new</span> C();
c.A();</pre>
<p>This time the compiler would report that class <strong>C</strong> does not contain a definition for method <strong>A()</strong>. We get the error because the explicit implementation of <strong>I1.A()</strong> hides <strong>A()</strong> from the class. The only way to call <strong>I1.A()</strong> now is through&nbsp;<strong>C</strong>'s <strong>I1</strong> interface:</p><pre class="csharpcode">C c = <span class="kwrd">new</span> C();
I1 i1 = (I1)c;
i1.A();</pre>
<p>Explicit interface implementations are&nbsp;sometimes necessary when classes implement multiple interfaces with conflicting member definitions. A common example&nbsp;involves collection enumerators&nbsp;that implement <a title="System.Collections.IEnumerator" href="https://msdn2.microsoft.com/en-us/library/system.collections.ienumerator.aspx">System.Collections.IEnumerator</a> and <a title="System.Collections.Generic.IEnumerator" href="https://msdn2.microsoft.com/en-us/library/78dfe2yb.aspx">System.Collections.Generic.IEnumerator<t></a>. &nbsp;In this case both interfaces specify a get-accessor for the <a title="System.Collections.IEnumerator.Current" href="https://msdn2.microsoft.com/en-us/library/system.collections.ienumerator.current.aspx">Current</a> property.&nbsp;To create a class that compiles, at&nbsp;least one of the two get-accessors must be explicitly implemented.</p>
<p><strong>Hiding Interface Details. </strong></p>
<p>In some cases explicit interface implementation can be useful even when disambiguation is unnecessary. One example is to use an explicit implementation to hide the details of an interface that the class developer considers private. While the level of privacy is not as great as that afforded by the <a title="private (C# Reference)" href="https://msdn2.microsoft.com/en-us/library/st6sy9xe.aspx">private</a> keyword, it can be useful in some circumstances. Listing&nbsp;5 shows a common pattern involving <a title="IDisposable Interface" href="https://msdn2.microsoft.com/en-us/library/system.idisposable.aspx">IDisposable</a>. In this case, the <strong>Dispose()</strong> method is hidden by explicit implementation because&nbsp;the method&nbsp;is really an implementation detail that is not germane to the users of class <strong>MyFile</strong>. At the very least, the explicit implementation keeps the interface members out of the class' <a title="Using IntelliSense" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsintro7/html/vcovrautomaticstatementcompletion.asp">Intellisense</a> list. </p>
<p><strong>Listing 5.&nbsp;Using explicit implementation to hide&nbsp;the details of IDisposable.</strong></p><pre class="csharpcode"><span class="kwrd">interface</span> IDisposable
{
    <span class="kwrd">void</span> Dispose();
}

<span class="kwrd">class</span> MyFile : IDisposable
{
    <span class="kwrd">void</span> IDisposable.Dispose()
    {
        Close();
    }

    <span class="kwrd">public</span> <span class="kwrd">void</span> Close()
    {
        <span class="rem">// Do what's necessary to close the file</span>
        System.GC.SuppressFinalize(<span class="kwrd">this</span>);
    }
}
</pre>
<p>You can read more about implicit and explicit interface implementations in this <a title="Explicit Interface Implementation Tutorial" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vcwlkExplicitInterfaceImplementationTutorial.asp">MSDN Tutorial</a> or in <a title="C# Language Specification 1.2" href="https://download.microsoft.com/download/5/e/5/5e58be0a-b02b-41ac-a4a3-7a22286214ff/csharp%20language%20specification%20v1.2.doc">Version 1.2 of the C# Language Specification</a>.</p>
<p><a href="https://download.microsoft.com/download/5/e/5/5e58be0a-b02b-41ac-a4a3-7a22286214ff/csharp language specification v1.2.doc"><strong></strong></a>&nbsp;</p>
<p>Hope this helps.</p>
<p>&nbsp;</p>
<p>-Mike Hopcroft</p>
<p>&nbsp;</p>
<a href="https://www.dotnetkicks.com/kick/?url=https://blogs.msdn.com/mhop/archive/2006/12/12/implicit-and-explicit-interface-implementations.aspx"><img src="https://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=https://blogs.msdn.com/mhop/archive/2006/12/12/implicit-and-explicit-interface-implementations.aspx" border="0" alt="kick it on DotNetKicks.com"></a>]]></content:encoded>
    </item>
    <item>
      <title>MSDN Community Content</title>
      <link>https://docs.microsoft.com/archive/blogs/mhop/msdn-community-content</link>
      <pubDate>Fri, 08 Dec 2006 02:04:00 GMT</pubDate>
      <dc:creator><![CDATA[mhop]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mhop/2006/12/08/msdn-community-content/</guid>
      <description><![CDATA[MSDN recently added Wiki functionality to the portion of the site dealing with Visual Studio 2005...]]></description>
      <content:encoded><![CDATA[<p><a title="MSDN" href="https://msdn2.microsoft.com/en-us/default.aspx">MSDN</a> recently added Wiki functionality to the portion of the site dealing with Visual Studio 2005 and .NET Framework 2.0. This already looks like it is going to be a great resource - at the time of this post, there were almost 1000 topics with Community Content from over 300 contributors.&nbsp;You can read more about it at <a title="MSDN Community Content FAQ" href="https://msdn2.microsoft.com/en-us/library/communitymsdnwikifaq.aspx">MSDN Community Content FAQ</a>.</p>
<p>Here's a sample screenshot of a community content block on an <a title="Implement ISerializable correctly" href="https://msdn2.microsoft.com/en-us/library/ms182342(vs.80).aspx">MSDN library page</a> (click the image to see a full size version).</p>
<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/MSDNCommunityContent_14492/image03.png" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/MSDNCommunityContent_14492/image0_thumb3.png" width="240" height="233" /></a></p>
<p>Hope this helps.</p>
<p>&nbsp;</p>
<p>-Mike</p>
<p><a href="https://www.dotnetkicks.com/kick/?url=https://blogs.msdn.com/mhop/archive/2006/12/07/msdn-community-content.aspx"><img border="0" alt="kick it on DotNetKicks.com" src="https://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=https://blogs.msdn.com/mhop/archive/2006/12/07/msdn-community-content.aspx" /></a></p>]]></content:encoded>
    </item>
    <item>
      <title>Home Automation Part 2 – Making Basic Measurements</title>
      <link>https://docs.microsoft.com/archive/blogs/mhop/home-automation-part-2-making-basic-measurements</link>
      <pubDate>Wed, 06 Dec 2006 04:39:00 GMT</pubDate>
      <dc:creator><![CDATA[mhop]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mhop/2006/12/06/home-automation-part-2-making-basic-measurements/</guid>
      <description><![CDATA[&#160;  In the previous installment I described my decision to build a temperature and humidity...]]></description>
      <content:encoded><![CDATA[<p mce_keep="true">&#160;</p>  <p>In the <a title="Home Automation Part 1 - Burning $200 of Propane" href="https://blogs.msdn.com/mhop/archive/2006/11/27/home-automation-part-1-burning-200-of-propane.aspx" mce_href="https://blogs.msdn.com/mhop/archive/2006/11/27/home-automation-part-1-burning-200-of-propane.aspx">previous installment</a> I described my decision to build a temperature and humidity sensor network using modules from <a title="IButtonLink.com" href="https://www.ibuttonlink.com/" target="_blank" mce_href="https://www.ibuttonlink.com/">IButtonLink.com</a>. The heart<span style="color: rgb(255, 0, 0);" color="#ff0000"> </span><span style="color: rgb(0, 0, 0);" color="#000000">of the system is the </span><a title="Link45" href="https://www.ibuttonlink.com/Link_Details.htm" target="_blank" mce_href="https://www.ibuttonlink.com/Link_Details.htm"><span style="color: rgb(0, 0, 0);" color="#000000">Link45</span></a> which connects the PC’s serial port to the sensor network and provides an ASCII interface to the sensors.</p>  <p>In previous home automation projects using .NET 1.1 I had no built-in class to access the serial port and therefore had to rely on solutions like VB6’s <a title="VCTERM Sample: Uses the Microsoft Communications ActiveX Control" href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcsample/html/_sample_mfc_vcterm.asp" mce_href="https://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcsample/html/_sample_mfc_vcterm.asp">MsComm32.ocx</a> or <a title="Corrado Cavalli&#39;s blog" href="https://blogs.ugidotnet.org/ccavalli" target="_blank" mce_href="https://blogs.ugidotnet.org/ccavalli">Corrado Cavalli’s</a> excellent <a title="Serial Communications in VB.NET" href="https://www.codeworks.it/net/VBNetRs232.htm" target="_blank" mce_href="https://www.codeworks.it/net/VBNetRs232.htm">CRs232 class</a>. For this project I decided to use <a title=".NET Framework Developer Center" href="https://msdn2.microsoft.com/en-us/netframework/default.aspx" mce_href="https://msdn2.microsoft.com/en-us/netframework/default.aspx">.NET Framework 2.0</a> so that I could try out the new <a title="SerialPort Class  (System.IO.Ports)" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.aspx" target="_blank" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.aspx">System.IO.Ports.SerialPort</a>class.</p>  <p>I needed to familiarize myself with the <a title="Link45" href="https://www.ibuttonlink.com/Link_Details.htm" target="_blank" mce_href="https://www.ibuttonlink.com/Link_Details.htm"><span style="color: rgb(0, 0, 0);" color="#000000">Link45</span></a> and learn how to enumerate the sensors on the network and take a reading from an individual sensor. With this in mind, I started by implementing a Super-Simple Serial Console that would let me type commands to the <a title="Link45" href="https://www.ibuttonlink.com/Link_Details.htm" target="_blank" mce_href="https://www.ibuttonlink.com/Link_Details.htm"><span style="color: rgb(0, 0, 0);" color="#000000">Link45</span></a> and see its responses in the console window. Most of the code was straight forward (see Listing 1, below) but I did run into a few gotchas related to serial port settings, <a title="Link45" href="https://www.ibuttonlink.com/Link_Details.htm" target="_blank" mce_href="https://www.ibuttonlink.com/Link_Details.htm"><span style="color: rgb(0, 0, 0);" color="#000000">Link45</span></a> initialization, and multi-threading.</p>  <p><strong>Listing 1. The Super-Simple Serial Console consists of about 100 lines of code.</strong></p>  <div class="csharpcode">   <div class="csharpcode">     <pre><span class="lnum">   1:  </span><span class="kwrd">using</span> System;</pre>

    <pre><span class="lnum">   2:  </span><span class="kwrd">using</span> System.IO.Ports;</pre>

    <pre><span class="lnum">   3:  </span><span class="kwrd">using</span> System.Threading;</pre>

    <pre><span class="lnum">   4:  </span> </pre>

    <pre><span class="lnum">   5:  </span><span class="kwrd">namespace</span> s3c</pre>

    <pre><span class="lnum">   6:  </span>{</pre>

    <pre><span class="lnum">   7:  </span>    <span class="rem">// Super-simple Serial Console</span></pre>

    <pre><span class="lnum">   8:  </span>    <span class="rem">// Provides an interactive console session with an iButtonLink Link45.</span></pre>

    <pre><span class="lnum">   9:  </span>    <span class="kwrd">class</span> S3C</pre>

    <pre><span class="lnum">  10:  </span>     {</pre>

    <pre><span class="lnum">  11:  </span>         <span class="kwrd">private</span> <span class="kwrd">int</span> nCharsReceived;</pre>

    <pre><span class="lnum">  12:  </span>         <span class="kwrd">private</span> SerialPort port;</pre>

    <pre><span class="lnum">  13:  </span>  </pre>

    <pre><span class="lnum">  14:  </span>         <span class="kwrd">public</span> <span class="kwrd">void</span> Run()</pre>

    <pre><span class="lnum">  15:  </span>         {</pre>

    <pre><span class="lnum">  16:  </span>             Console.WriteLine(<span class="str">&quot;Super-Simple Serial Console&quot;</span>);</pre>

    <pre><span class="lnum">  17:  </span>             <span class="kwrd">try</span></pre>

    <pre><span class="lnum">  18:  </span>             {</pre>

    <pre><span class="lnum">  19:  </span>                 Open();</pre>

    <pre><span class="lnum">  20:  </span>  </pre>

    <pre><span class="lnum">  21:  </span>                 <span class="kwrd">while</span> (<span class="kwrd">true</span>)</pre>

    <pre><span class="lnum">  22:  </span>                 {</pre>

    <pre><span class="lnum">  23:  </span>                     <span class="rem">// Show &gt; prompt, read line from console and transmit to serial port.</span></pre>

    <pre><span class="lnum">  24:  </span>                     Console.Write(<span class="str">&quot;&gt;&quot;</span>);</pre>

    <pre><span class="lnum">  25:  </span>                     String line = System.Console.ReadLine();</pre>

    <pre><span class="lnum">  26:  </span>                     <span class="kwrd">if</span> (line.Length == 0)</pre>

    <pre><span class="lnum">  27:  </span>                         <span class="kwrd">return</span>;</pre>

    <pre><span class="lnum">  28:  </span>  </pre>

    <pre><span class="lnum">  29:  </span>                     nCharsReceived = 0;</pre>

    <pre><span class="lnum">  30:  </span>                     port.Write(line);</pre>

    <pre><span class="lnum">  31:  </span>  </pre>

    <pre><span class="lnum">  32:  </span>                     <span class="rem">// Wait until 200ms after the last data received from port before </span></pre>

    <pre><span class="lnum">  33:  </span>                     <span class="rem">// prompting for next line.</span></pre>

    <pre><span class="lnum">  34:  </span>                     <span class="kwrd">while</span> (<span class="kwrd">true</span>)</pre>

    <pre><span class="lnum">  35:  </span>                     {</pre>

    <pre><span class="lnum">  36:  </span>                         <span class="kwrd">int</span> n = nCharsReceived;</pre>

    <pre><span class="lnum">  37:  </span>                         Thread.Sleep(200);</pre>

    <pre><span class="lnum">  38:  </span>                         <span class="kwrd">if</span> (n == nCharsReceived)</pre>

    <pre><span class="lnum">  39:  </span>                             <span class="kwrd">break</span>;</pre>

    <pre><span class="lnum">  40:  </span>                     }</pre>

    <pre><span class="lnum">  41:  </span>                 }</pre>

    <pre><span class="lnum">  42:  </span>             }</pre>

    <pre><span class="lnum">  43:  </span>             <span class="kwrd">finally</span></pre>

    <pre><span class="lnum">  44:  </span>             {</pre>

    <pre><span class="lnum">  45:  </span>                 <span class="kwrd">if</span> (port != <span class="kwrd">null</span> &amp;&amp; port.IsOpen)</pre>

    <pre><span class="lnum">  46:  </span>                     port.Close();</pre>

    <pre><span class="lnum">  47:  </span>             }</pre>

    <pre><span class="lnum">  48:  </span>         }</pre>

    <pre><span class="lnum">  49:  </span>  </pre>

    <pre><span class="lnum">  50:  </span>         <span class="kwrd">public</span> <span class="kwrd">void</span> Open()</pre>

    <pre><span class="lnum">  51:  </span>         {</pre>

    <pre><span class="lnum">  52:  </span>             port = <span class="kwrd">new</span> SerialPort(<span class="str">&quot;COM1&quot;</span>, 9600, Parity.None, 8, StopBits.One);</pre>

    <pre><span class="lnum">  53:  </span>  </pre>

    <pre><span class="lnum">  54:  </span>             <span class="rem">// The iButton Link45 needs DTR and RTS enabled.</span></pre>

    <pre><span class="lnum">  55:  </span>             port.DtrEnable = <span class="kwrd">true</span>;</pre>

    <pre><span class="lnum">  56:  </span>             port.RtsEnable = <span class="kwrd">true</span>;</pre>

    <pre><span class="lnum">  57:  </span>  </pre>

    <pre><span class="lnum">  58:  </span>             <span class="rem">// Hook up callback to display data received from Link45</span></pre>

    <pre><span class="lnum">  59:  </span>             port.DataReceived += <span class="kwrd">new</span> SerialDataReceivedEventHandler(port_DataReceived);</pre>

    <pre><span class="lnum">  60:  </span>  </pre>

    <pre><span class="lnum">  61:  </span>             <span class="rem">// The serial port is now configured and ready to be opened.</span></pre>

    <pre><span class="lnum">  62:  </span>             port.Open();</pre>

    <pre><span class="lnum">  63:  </span>  </pre>

    <pre><span class="lnum">  64:  </span>             <span class="rem">// Shock the Link45 to life by sending a break.</span></pre>

    <pre><span class="lnum">  65:  </span>             port.BreakState = <span class="kwrd">true</span>;</pre>

    <pre><span class="lnum">  66:  </span>             port.BreakState = <span class="kwrd">false</span>;</pre>

    <pre><span class="lnum">  67:  </span>         }</pre>

    <pre><span class="lnum">  68:  </span>  </pre>

    <pre><span class="lnum">  69:  </span>         <span class="kwrd">public</span> <span class="kwrd">void</span> Close()</pre>

    <pre><span class="lnum">  70:  </span>         {</pre>

    <pre><span class="lnum">  71:  </span>             port.Close();</pre>

    <pre><span class="lnum">  72:  </span>         }</pre>

    <pre><span class="lnum">  73:  </span>  </pre>

    <pre><span class="lnum">  74:  </span>         <span class="kwrd">void</span> port_DataReceived(<span class="kwrd">object</span> sender, SerialDataReceivedEventArgs e)</pre>

    <pre><span class="lnum">  75:  </span>         {</pre>

    <pre><span class="lnum">  76:  </span>             <span class="kwrd">string</span> s = port.ReadExisting();</pre>

    <pre><span class="lnum">  77:  </span>             <span class="kwrd">if</span> (s != <span class="kwrd">null</span>)</pre>

    <pre><span class="lnum">  78:  </span>             {</pre>

    <pre><span class="lnum">  79:  </span>                 nCharsReceived += s.Length;</pre>

    <pre><span class="lnum">  80:  </span>                 Console.Write(s);</pre>

    <pre><span class="lnum">  81:  </span>             }</pre>

    <pre><span class="lnum">  82:  </span>         }</pre>

    <pre><span class="lnum">  83:  </span>     }</pre>

    <pre><span class="lnum">  84:  </span>  </pre>

    <pre><span class="lnum">  85:  </span>     <span class="kwrd">class</span> Program</pre>

    <pre><span class="lnum">  86:  </span>     {</pre>

    <pre><span class="lnum">  87:  </span>  </pre>

    <pre><span class="lnum">  88:  </span>         <span class="kwrd">static</span> <span class="kwrd">void</span> Main(<span class="kwrd">string</span>[] args)</pre>

    <pre><span class="lnum">  89:  </span>         {</pre>

    <pre><span class="lnum">  90:  </span>             S3C s3c = <span class="kwrd">new</span> S3C();</pre>

    <pre><span class="lnum">  91:  </span>             s3c.Run();</pre>

    <pre><span class="lnum">  92:  </span>         }</pre>

    <pre><span class="lnum">  93:  </span>  </pre>

    <pre><span class="lnum">  94:  </span>     }</pre>

    <pre><span class="lnum">  95:  </span> }</pre>
  </div>
  <style type="text/css">.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; } </style></div>

<p mce_keep="true">&#160;</p>

<p>Let's walk through the code in execution-order. The program entry point is the Main() function at at line 88. Main() just news up an S3C object (S3C is short for Super-Simple Serial Console) and calls it's Run() method. The Run() method does four things:</p>

<ul>
  <li>prints a welcome message at line 16.</li>

  <li>initializes the serial port by calling Open() at line 19.</li>

  <li>performs the main input and serial port write loop in lines 21-41.</li>

  <li>closes the serial port in lines 43-47.</li>
</ul>

<p><strong>Initializing the Serial Port.</strong> My first challenge was getting the serial port settings correct in the Open() method, lines 50-67. The <a title="Link45" href="https://www.ibuttonlink.com/Link_Details.htm" target="_blank" mce_href="https://www.ibuttonlink.com/Link_Details.htm"><span style="color: rgb(0, 0, 0);" color="#000000">Link45</span></a> had some of the port settings conveniently printed on the side of the device. These included 9600 baud, no parity and 8 bits of data. I figured out the stop bits by trial and error. All of these values were passed to the constructor of the <a title="SerialPort Class (System.IO.Ports)" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.aspx" target="_blank" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.aspx">System.IO.Ports.SerialPort</a> in line 52. I also found that I needed to enable <a title="DTR Enable Property" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.dtrenable.aspx" target="_blank" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.dtrenable.aspx">DTR</a> and <a title="RTS Enable Property" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.rtsenable.aspx" target="_blank" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.rtsenable.aspx">RTS</a> which I do on lines 55 and 56. If you want to learn more about serial port esoterics in general, check out <a title="Wikipedia RS232" href="https://en.wikipedia.org/wiki/RS232" mce_href="https://en.wikipedia.org/wiki/RS232">Wikipedia RS323</a>.</p>

<p>After creating and configuring the serial port, I wire up a handler for the port's <a title="SerialPort.DataReceived Event" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx" target="_blank" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx">DataReceived</a> event on line 59. This is where the multithreading comes in. Serial port communications are inherently asynchronous - once you transmit some data your main thread continues on to do other work and at some point in the future when a response arrives back at the port, the <a title="SerialPort.DataReceived Event" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx" target="_blank" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx">DataReceived</a> event is fired on another thread, which results in a call to port_DataReceived() which is defined on line 74.</p>

<p>Once the event handler is wired up, it is time to actually open the serial port (line 62). I thought I was done configuring the port at this point, but I found in my experiments that some Link45 commands such as the help command would sometimes fail if issued before a sensor read command. I ended up fixing this problem by toggling the serial port's <a title="BreakState Property" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.breakstate.aspx" target="_blank" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.breakstate.aspx">break state</a> to true and then back to false (lines 65-66). This seems to have the effect of resetting the communication channel to the Link45 and ensures that all of the Link45 commands work consistently the first time.</p>

<p><strong>The Main Loop.</strong> After initializing the serial port, we enter the main loop on line 21. The loop runs until an empty input line is detected (lines 26-27) or an exception is thrown (lines 43-47). At the top of the loop we print a prompt and get user input (lines 24-25) and then send the user's text to the serial port (line 30). After sending the text, we wait a brief period for a response to be displayed (lines 34-40) and then head back to the top of the loop to prompt the user for more input.</p>

<p><strong>A Bit of Multithreading.</strong> Responses from the Link45 trigger the serial port's <a title="SerialPort.DataReceived Event" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx" target="_blank" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx">DataReceived</a> event. For the Super-Simple Serial Console, the role of the <a title="SerialPort.DataReceived Event" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx" target="_blank" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx">DataReceived</a> event handler is simple - it just reads any data that is available in the serial port's input buffer and then prints that data to the console. This all happens on lines 74-82. The only part that isn't completely straight forward is line 79:</p>

<div class="csharpcode">
  <pre><span class="lnum"> 79: </span>                nCharsReceived += s.Length;</pre>
</div>

<p>This is where the <a title="SerialPort.DataReceived Event" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx" target="_blank" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx">DataReceived</a> thread communicates with the main thread. The reason we need some sort of handshaking between the threads is that we'd like the serial port responses to be interleaved with the user input - basically a repeating prompt-input-response pattern. Without this handshaking, the prompt for the next command would be printed before the response from the current command.</p>

<p>One way to accomplish this interleaving is to blindly Sleep() for a fixed amount of time in the main loop after every command is transmitted to the serial port. This approach will work with a long enough sleep, but it leads to a sluggish user experience because every Sleep() needs to be long enough to wait for the slowest <a title="Link45" href="https://www.ibuttonlink.com/Link_Details.htm" target="_blank" mce_href="https://www.ibuttonlink.com/Link_Details.htm"><span style="color: rgb(0, 0, 0);" color="#000000">Link45</span></a> command. Experiments showed that the <a title="Link45" href="https://www.ibuttonlink.com/Link_Details.htm" target="_blank" mce_href="https://www.ibuttonlink.com/Link_Details.htm"><span style="color: rgb(0, 0, 0);" color="#000000">Link45</span></a> was always pretty responsive, but that some commands resulted in a verbose response that could take a second or more to receive.</p>

<p>My approach was to wait 200ms beyond the time the last character was received. If, after 200ms, no additional characters had been received, I would assume the response was complete and head back up to the top of the loop for more user input. I used the <strong><em>nCharsReceived</em></strong> variable to track the number of characters received while waiting. I clear <strong><em>nCharsReceived</em></strong> (line 29) immediately before writing to the serial port. The <a title="SerialPort.DataReceived Event" href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx" target="_blank" mce_href="https://msdn2.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx">DataReceived</a> event handler updates <strong><em>nCharsReceived</em></strong> on line 79. Lines 34-39 in the main loop alternately Sleep() for 200ms and check <em><strong>nCharsReceived</strong></em> for more data until a Sleep() occurs with no new data received. Technically speaking one should probably protect <strong><em>nCharsReceived</em></strong> with a lock in case we ever encounter an architecture where integer writes aren't atomic.</p>

<p><strong>Putting It All Together.</strong>Once I had the Super-Simple Serial Console working, I proceeded to wire up a pair of sensors to the serial port in the back of my laptop. The connections were easy since the sensors have RJ-45 connectors. Figure 1 shows the setup.</p>

<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/SensorsAndLaptop2.jpg" mce_href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/SensorsAndLaptop2.jpg"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/SensorsAndLaptop_thumb2.jpg" width="640" height="480" mce_src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/SensorsAndLaptop_thumb2.jpg" /></a></p>

<p><strong>Figure 1.&#160; CAT-5 networking cable connects a pair of sensors to the serial port via the <a title="Link45" href="https://www.ibuttonlink.com/Link_Details.htm" target="_blank" mce_href="https://www.ibuttonlink.com/Link_Details.htm"><span style="color: rgb(0, 0, 0);" color="#000000">Link45</span></a>.</strong></p>

<p>After plugging in the sensors I fired up the Super-Simple Serial Console. I began by typing the character <b>h</b> to see the list of commands available. The transcript in Figure 2 shows the response from the <a title="Link45" href="https://www.ibuttonlink.com/Link_Details.htm" target="_blank" mce_href="https://www.ibuttonlink.com/Link_Details.htm"><span style="color: rgb(0, 0, 0);" color="#000000">Link45</span></a>. You can read more about the available commands in the <a title="LinkTH Users Manual V10e" href="https://www.ibuttonlink.com/PDFs/LinkTH%20Users%20Manual%20V10e.pdf." mce_href="https://www.ibuttonlink.com/PDFs/LinkTH%20Users%20Manual%20V10e.pdf.">Link45 Users Manual</a>.&#160; </p>

<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/image01.png" mce_href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/image01.png"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/image0_thumb1.png" width="709" height="464" mce_src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/image0_thumb1.png" /></a></p>

<p><strong>Figure 2. First communications with the Link45.</strong></p>

<p>To get the list of sensors on the network I typed the character <strong>I</strong>, requesting that the <a title="Link45" href="https://www.ibuttonlink.com/Link_Details.htm" target="_blank" mce_href="https://www.ibuttonlink.com/Link_Details.htm"><span style="color: rgb(0, 0, 0);" color="#000000">Link45</span></a> report the sensor inventory. The results are shown in Figure 3. Each sensor appears on a line consisting of a 16 hex digit sensor ID followed by a 2 digit sensor type. My network shows two temperature+humidity sensors. Here’s the cheat sheet for the sensor types:</p>

<ul>
  <li>00 – temperature</li>

  <li>19 – temperature + humidity</li>

  <li>1A – temperature + voltage</li>

  <li>1B – temperature + light</li>
</ul>

<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/image03.png" mce_href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/image03.png"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/image0_thumb3.png" width="707" height="204" mce_src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/image0_thumb3.png" /></a></p>

<p><strong>Figure 3. The I command reports the list of sensors on the network.</strong></p>

<p>Finally, I used the <strong>D</strong> command to request temperature and humidity readings from all sensors on the network. Figure 4 shows the results. According to the <a title="Link45" href="https://www.ibuttonlink.com/Link_Details.htm" target="_blank" mce_href="https://www.ibuttonlink.com/Link_Details.htm"><span style="color: rgb(0, 0, 0);" color="#000000">Link45</span></a> documentation, the data returned for each sensor is of the form</p>

<blockquote>
  <p>xxxxxxxxxxxxxxxx ss,ccc.cc,fff.ff,hhh</p>
</blockquote>

<p>where</p>

<ul>
  <li><em>xxxxxxxxxxxxxxxx</em>is a 16 digit hexadecimal sensor ID</li>

  <li><em>ss</em>is the sensor type</li>

  <li><em>ccc.cc</em>is the temperature in degrees Celsius</li>

  <li><em>fff.ff</em>is the temperature in degrees Fahrenheit</li>

  <li><em>hhh</em> is the humidity</li>
</ul>

<p>My network shows that the temperatures near my computer are in the mid 60s and with humidity around 44%.</p>

<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/image05.png" mce_href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/image05.png"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/image0_thumb5.png" width="706" height="126" mce_src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/HomeAutomationPart2MakingBasicMeasuremen_9C3B/image0_thumb5.png" /></a></p>

<p><strong>Figure 4. The D command takes temperature and humidity readings from all sensors.</strong></p>

<p>The <a title="Link45" href="https://www.ibuttonlink.com/Link_Details.htm" target="_blank" mce_href="https://www.ibuttonlink.com/Link_Details.htm"><span style="color: rgb(0, 0, 0);" color="#000000">Link45</span></a> has a lot of functionality and accepts many more commands than the ones I've shown here. You can learn more from the <a title="LinkTH Users Manual V10e" href="https://www.ibuttonlink.com/PDFs/LinkTH%20Users%20Manual%20V10e.pdf." mce_href="https://www.ibuttonlink.com/PDFs/LinkTH%20Users%20Manual%20V10e.pdf.">Link45 Users Manual</a>.&#160; </p>

<p>With the code from the Super-Simple Serial Console and the <a title="Link45" href="https://www.ibuttonlink.com/Link_Details.htm" target="_blank" mce_href="https://www.ibuttonlink.com/Link_Details.htm"><span style="color: rgb(0, 0, 0);" color="#000000">Link45</span></a> commands for sensor inventory and sensor reading, we have all the building blocks we need to write a program to monitor the temperature and humidity.</p>

<p><strong>Next installment: </strong><a id="bp___ctl00___RecentPosts___postlist___EntryItems_ctl00_PostTitle" title="Home Automation Part 3 - Using Regular Expressions to Parse Sensor Data " href="https://blogs.msdn.com/mhop/archive/2007/01/07/home-automation-part-3-using-regular-expressions-to-parse-sensor-data.aspx" mce_href="https://blogs.msdn.com/mhop/archive/2007/01/07/home-automation-part-3-using-regular-expressions-to-parse-sensor-data.aspx"><span style="color: rgb(68, 68, 51);" color="#444433">Using Regular Expressions to Parse Sensor Data</span></a></p>

<p><a href="https://www.dotnetkicks.com/kick/?url=https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx" mce_href="https://www.dotnetkicks.com/kick/?url=https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx"><img border="0" alt="kick it on DotNetKicks.com" src="https://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx" mce_src="https://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx" /></a></p>]]></content:encoded>
    </item>
    <item>
      <title>MSDN Online Chat: LINQ to SQL</title>
      <link>https://docs.microsoft.com/archive/blogs/mhop/msdn-online-chat-linq-to-sql</link>
      <pubDate>Sun, 03 Dec 2006 22:45:20 GMT</pubDate>
      <dc:creator><![CDATA[mhop]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mhop/2006/12/03/msdn-online-chat-linq-to-sql/</guid>
      <description><![CDATA[Members of the C# team will be hosting an online chat session about LINQ to SQL on Tuesday, December...]]></description>
      <content:encoded><![CDATA[<p>Members of the C# team will be hosting an online chat session about <a title="The LINQ Project" href="https://msdn2.microsoft.com/en-us/netframework/aa904594.aspx">LINQ to SQL</a> on Tuesday, December 12, 2006. Here's the description:</p> <blockquote> <p>The LINQ Project is a codename for a set of extensions to the .NET Framework that encompass language-integrated query, set, and transform operations. LINQ to SQL is a component of LINQ which allows access to data stored in relational databases. We’re actively designing and developing this technology - show up and join the LINQ to SQL team to participate in that process or just get a better understanding!</p></blockquote> <p>For more information go to <a title="https://msdn.microsoft.com/chats/" href="https://msdn.microsoft.com/chats/">https://msdn.microsoft.com/chats/</a>. </p>]]></content:encoded>
    </item>
    <item>
      <title>Programming Projects</title>
      <link>https://docs.microsoft.com/archive/blogs/mhop/programming-projects</link>
      <pubDate>Fri, 01 Dec 2006 08:13:00 GMT</pubDate>
      <dc:creator><![CDATA[mhop]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mhop/2006/12/01/programming-projects/</guid>
      <description><![CDATA[Home Automation

Home Automation Part 1 - Burning $200 of propane 
Home Automation Part 2 -...]]></description>
      <content:encoded><![CDATA[<H3>Home Automation</H3>
<UL>
<LI><A id=bp___ctl00___RecentPosts___postlist___EntryItems_ctl00_PostTitle href="https://blogs.msdn.com/mhop/archive/2006/11/27/home-automation-part-1-burning-200-of-propane.aspx" mce_href="https://blogs.msdn.com/mhop/archive/2006/11/27/home-automation-part-1-burning-200-of-propane.aspx"><FONT color=#444433>Home Automation Part 1 - Burning $200 of propane</FONT></A> </LI>
<LI><A class="" title="Home Automation Part 2 - Making Basic Measurements" href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx" mce_href="https://blogs.msdn.com/mhop/archive/2006/12/06/home-automation-part-2-making-basic-measurements.aspx">Home Automation Part 2 - Making Basic Measurements</A></LI>
<LI><A id=bp___ctl00___RecentPosts___postlist___EntryItems_ctl00_PostTitle href="https://blogs.msdn.com/mhop/archive/2007/01/07/home-automation-part-3-using-regular-expressions-to-parse-sensor-data.aspx"><FONT color=#444433>Home Automation Part 3 - Using Regular Expressions to Parse Sensor Data</FONT></A> </LI></UL>
<P mce_keep="true">&nbsp;</P>]]></content:encoded>
    </item>
    <item>
      <title>New for Visual Studio 2005</title>
      <link>https://docs.microsoft.com/archive/blogs/mhop/new-for-visual-studio-2005</link>
      <pubDate>Fri, 01 Dec 2006 00:16:00 GMT</pubDate>
      <dc:creator><![CDATA[mhop]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mhop/2006/12/01/new-for-visual-studio-2005/</guid>
      <description><![CDATA[IDE Features

New For VS2005 - Abstract Stub Generation 
Language Features

(coming soon)]]></description>
      <content:encoded><![CDATA[<H3>IDE Features</H3>
<UL>
<LI><A id=bp___ctl00___RecentPosts___postlist___EntryItems_ctl00_PostTitle href="https://blogs.msdn.com/mhop/archive/2006/11/29/new-for-vs2005-abstract-stub-generation.aspx" mce_href="https://blogs.msdn.com/mhop/archive/2006/11/29/new-for-vs2005-abstract-stub-generation.aspx">New For VS2005 - Abstract Stub Generation</A> </LI></UL>
<H3>Language Features</H3>
<UL>
<LI>(coming soon)</LI></UL>]]></content:encoded>
    </item>
    <item>
      <title>New For VS2005 - Abstract Stub Generation</title>
      <link>https://docs.microsoft.com/archive/blogs/mhop/new-for-vs2005-abstract-stub-generation</link>
      <pubDate>Thu, 30 Nov 2006 21:52:00 GMT</pubDate>
      <dc:creator><![CDATA[mhop]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mhop/2006/11/30/new-for-vs2005-abstract-stub-generation/</guid>
      <description><![CDATA[Visual Studio 2005 includes a new feature to generate stubs for methods in an abstract base class....]]></description>
      <content:encoded><![CDATA[<p><a title="Visual Studio 2005" href="https://msdn.microsoft.com/vstudio/vshome.aspx">Visual Studio 2005</a> includes a new feature to generate stubs for methods in an <a title="Abstract and sealed classes and class members (C# programming guide)" href="https://msdn2.microsoft.com/en-us/library/ms173150.aspx">abstract base class</a>. Here's an example of how it works.</p>
<p>Suppose you want to create a class called MyDerivedClass that inherits from an abstract class called MyAbstractClass:</p>
<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/NewForVS2005AbstractStubGeneration_C327/image056.png" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/NewForVS2005AbstractStubGeneration_C327/image0_thumb34.png" width="408" height="142" /></a>&nbsp;</p>
<p>Before <a title="Visual Studio 2005" href="https://msdn.microsoft.com/vstudio/vshome.aspx">Visual Studio 2005</a>, you would have had to look up and then type in&nbsp;the function&nbsp;prototypes for each of the abstract methods in the&nbsp;inheritance chain for MyDerivedClass. Just finding these methods to implement can be hard because the inheritance chain may include multiple abstract classes and any ancestor class can implement any abstract method. If you had the source code to all of the classes in the inheritance chain you could figure out which&nbsp;methods were still abstract for your class&nbsp;and then&nbsp;go to their definitions and copy-paste the function prototypes, replacing the <strong><em><a title="abstract (C# reference)" href="https://msdn2.microsoft.com/en-us/library/sf985hc5.aspx">abstract</a></em></strong> keyword with <em><strong><a title="override (C# reference)" href="https://msdn2.microsoft.com/en-us/library/ebca9ah3.aspx">override</a>. </strong></em>If you didn't have the source code for the entire inheritance chain, you might end up using the Object viewer to identify and copy the function definitions. Either way, you would be in for a bit of work.</p>
<p>In <a title="Visual Studio 2005" href="https://msdn.microsoft.com/vstudio/vshome.aspx">Visual Studio 2005</a>, a small blue rectangle called a smart tag appears whenever you start to declare a class that derives from an abstract type:</p>
<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/NewForVS2005AbstractStubGeneration_C327/image058.png" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/NewForVS2005AbstractStubGeneration_C327/image0_thumb36.png" width="408" height="200" /></a>&nbsp;</p>
<p>Hovering over the tag or pressing Shift+Alt+F10 will produce a menu of alternatives for implementing the abstract methods:</p>
<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/NewForVS2005AbstractStubGeneration_C327/image060.png" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/NewForVS2005AbstractStubGeneration_C327/image0_thumb38.png" width="510" height="191" /></a>&nbsp;</p>
<p>Clicking on the down arrow opens the menu, which in this example shows a single option:</p>
<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/NewForVS2005AbstractStubGeneration_C327/image066.png" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/NewForVS2005AbstractStubGeneration_C327/image0_thumb44.png" width="514" height="202" /></a>&nbsp;</p>
<p>Invoking this option implements stubs for&nbsp;the overrides&nbsp;of the abstract methods as follows:</p>
<p><a href="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/NewForVS2005AbstractStubGeneration_C327/image064.png" atomicselection="true"><img src="https://www.michaeljhopcroft.com/MSDNBlogImages/Images/NewForVS2005AbstractStubGeneration_C327/image0_thumb42.png" width="651" height="332" /></a></p>
<p>It&rsquo;s that easy. Now all you need to do is fill in the implementation for each method and you are up and running.</p>
<p>Hope this helps.</p>
<p>Mike&nbsp;</p>
<p>&nbsp;</p>
<p><a href="https://www.dotnetkicks.com/kick/?url=https://blogs.msdn.com/mhop/archive/2006/11/30/new-for-vs2005-abstract-stub-generation.aspx"><img border="0" alt="kick it on DotNetKicks.com" src="https://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=https://blogs.msdn.com/mhop/archive/2006/11/30/new-for-vs2005-abstract-stub-generation.aspx" /></a></p>]]></content:encoded>
    </item>
  </channel>
</rss>