UPDATE: The feed changed a little bit from the first time I published the format

I made changes to the twitter feed format to match the game for the FIRST FRC 2010 Season.  You can follow the tweets for this season at http://twitter.com/Frcfms 

The new format is as follows:

#FRCABC - where ABC is the Event Code. Each event has a unique code.
TY X - where x is P for Practice Q for qualification E for Elimination
MC X - where X is the match number
RF XXX - where XXX is the Red Final Score
BF XXX - where XXX is the Blue Final Score
RE XXXX YYYY ZZZZ - where XXXX is red team 1 number, YYYY is red team 2 number, ZZZZ is red team 3 number
BL XXXX YYYY ZZZZ - where XXXX is blue team 1 number, YYYY is blue team 2 number, ZZZZ is blue team 3 number
RB X - where X is the Bonus the Referee gave to Red
BB X - where X is the Bonus the Referee gave to Blue
RP X - where X are the Penalties the Referee gave to Red
BP X - where X are the Penalties the Referee gave to Blue
RG X - where X is the Goals scored by Red
BG X - where X is the Goals scored by Blue
RGP X - where X is the Goal Penalties by Red
BGP X - where X is the Goal Penalties by Blue

Example tweet in text:

#FRCTEST TY Q MC 2 RF 5 BF 3 RE 3224 2119 547 BL 587 2420 342 RB 1 BB 1 RP 0 BP 0 RG 0 BG 5 RGP 2 BGP 1

I sure would like to know if anyone builds anything that parses these tweets.

At one of the Charlotte Alt.Net meetings I gave a presentation on how I utilized a simple Pub/Sub messaging architecture to allow for several applications to communicate across machine boundaries.  This blog post won’t be about that system I demoed at the meeting, but it will be about a suggested example that will get the Pub/Sub concept across in a simple way.

Requirements 

The system that is being built to demonstrate the Pub/Sub concept will fulfill the following requirements:

  • Simulate a BBQ Smoker
  • Monitor the temperature of a BBQ Smoker
  • Provide feedback at what temperature the Smoker is currently at.
  • Provide visual Alarm indicators that identify three states of the temperature
    • Low
    • Normal
    • High
  • Ability to have multiple smokers
  • Ability to have multiple monitors monitoring a single smoker

Pub/Sub Infrastructure

The Pub/Sub Infrastructure was taken from a previous MSDN article written by Juval Lowy.  The infrastructure uses WCF as the communications mechanism. The source code I have in my sample project might be a little different than what was in the original MSDN article so I will explain how it is organized in the Visual Studio Solution. 

First a little background on what makes up a Pub/Sub Messaging system.  A Pub/Sub Messaging system has three components: Broker, Publisher and Subscriber.

Broker

The broker is the enabler.  The broker’s job is to connect publishers with subscribers. The broker contains a list of subscribers and what messages they are interested in.  The broker exposes endpoints that allow for subscribers to subscribe to messages and a publisher to publish interesting messages.  In my example solution the broker is a WCF service that is hosted by a console application (Broker.ConsoleHost).  Since this is a WCF service it can also be hosted under IIS or a Windows Service just as easily.

The WCF Contract for messages that the broker accepts for the BBQ Smoker is as follows:

image    

Since the broker also manages what subscribers want to subscribe to a contract also exists for subscribers as follows:

image

Publisher

The only thing the publisher knows is that when it has anything to publish it simply sends the message to the Broker.  The publisher has no idea on the final destination of the message or if there even is a final destination.  This promotes a very decoupled system in that the publisher knows nothing about their subscribers.  In my example solution the publisher is the Smoker device and it publishes the, Smoker Alarm and Temperature Changed messages.  A Smoker Alarm message is published when the smoker reaches a temperature that is too low of too high.  A Temperature Changed message is published when the temperature of the smoker has changed at all. 

Since the Smoker Temperature is simulated by a slider on the UI here is the event that fires when the slider changes and publishes the Alarm and Temperature changed messages:

image

The _publish object in the above code snippet is simply a web service proxy that calls the broker.

Subscriber

A subscriber communicates with the broker to tell it what published messages it is interested in.  The subscriber in my example solution is the Smoker Monitor.  The job of the subscriber is to listen for Smoker Alarm and Temperature Changed messages and display information to the user when these messages arrive.  The Smoker Alarm message will turn the display Yellow when the temperature is too low and Red when the temperature is too high.  The temperature changed message will update the screen with the actual temperature that came from the smoker.

The subscriber needs to register the class that implements the interface (IMessage) that will be the callback that gets executed when either of messages are received.  In my example solution this is done in the constructor of the Form1 class in the Smoker Monitor project as shown below:

image

Additional logic exists in the SmokerAlarm (callback) method that sets the UI components to the proper color and text based on the alarm state as shown below:

image

Conclusion

Since the broker is capable of hooking up multiple subscribers to a single publisher you can run multiple monitors across multiple machines all monitoring the same smoker.  This is very powerful because the monitors could be providing the same feedback to the user just in a different location of the house or the monitor could be providing feedback via a different means. For example another monitor could be created that sent a text message or a twitter message when the alarm is published.  These new monitors can be added without changing the existing contract.  Even a third party could create a monitor that did some special thing on published messages and you could run their monitor without changing the broker or smoker.      

A zip that contains the entire code for the BBQ Smoker Monitor via Pub/Sub messaging can be found here.  Feel free to download the code and look at it in more detail.  Also take a look at the ReadMe.txt for additional information on how to run the application.

I hope to expand on this in a later project that will allow me to create an actual embedded device that can detect the temperature of a smoker instead of using a simulated Smoker Device.  This embedded device will have to be able to publish the messages to the broker so that a PC does not have to be connected to the smoker.

Doing agile development means deploying your application very frequently into many environments.  You might have several environments that all have different configuration settings.  Changing these settings by hand results in time consuming mistakes.  I have built a couple different console deployment tools over the years that handled this.  Usually you would run the console tool with a command line argument that would specify the environment that you wanted to configure and this tool would look up all the settings in a property file and make the changes in the app.config or web.config file.  I thought it would be fun to do something similar using powershell.

So what do I want this script to do? 

  • Keep environment specific settings in a property file
  • Support having 1 to N property files (i.e. Dev, Test, Build etc) for a project that is accepted as a parameter into the script
  • The web.config or app.config file is modified with the values that come from the property file
  • Support changing connection strings and application settings in version 1 of this script

The first steps in creating this script is to have a set of functions that can easily be used to set the entries in a config file.  I would use this script in all my projects that needed to have the ability to set connection and application settings.  This library of useful functions will be called Xml-Config.ps1

function Set-ConnectionString([string]$fileName, [string]$outFileName, [string]$name, [string]$value)
{

    # Load the config file up in memory
    [xml]$a = get-content $fileName;

    # Find the connection string to change
    $a.configuration.connectionstrings.selectsinglenode("add[@name='" + $name + "']")
       .connectionString = $value

    # Write it out to the new file
    Format-XML $a | out-file $outFileName
}
function Set-ConnectionString
([string]$fileName, [string]$outFileName, [string]$name, [string]$value)
{

    # Load the config file up in memory
    [xml]$a = get-content $fileName;

    # Find the cennection string to change
    $a.configuration.connectionstrings.selectsinglenode("add[@name='" + $name + "']")
             .connectionString = $value

    # Write it out to the new file
    Format-XML $a | out-file $outFileName
}
function Set-ApplicationSetting 
([string]$fileName, [string]$outFileName, [string]$name, [string]$value)
{

    # Load the config file up in memory
    [xml]$a = get-content $fileName;

    # Find the app settings item to change
    $a.configuration.appSettings.selectsinglenode("add[@key='" + $name + "']").value = $value

    # Write it out to the new file
    Format-XML $a | out-file $outFileName
}
function Format-XML ([xml]$xml, $indent=2) 
{ 
    $StringWriter = New-Object System.IO.StringWriter 
    $XmlWriter = New-Object System.XMl.XmlTextWriter $StringWriter 
    $xmlWriter.Formatting = "indented" 
    $xmlWriter.Indentation = $Indent 
    $xml.WriteContentTo($XmlWriter) 
    $XmlWriter.Flush() 
    $StringWriter.Flush() 
    Write-Output $StringWriter.ToString() 
}

Next I needed a script file that was specific to the software project.  I wouldn’t be re-using this script from project to project as it has very specific details that only apply to one project.  For example a software project might have a web.config for the web application but an app.config for a windows service.  It would be the job of this second script to know where these configs are located and tie the property values to the functions above.  In the following example the web.config has two settings that I want to change at deployment time (connection string and application setting).  These settings will be different for Test, Build and Development environments.  This script will be called dev.ps1.

dev.ps1

param([string]$propertyFile)

$workDir = Get-Location
. $workDir\Xml-Config.ps1
. $workDir\$propertyFile.ps1

# Change the connection string
Set-ConnectionString "web.config" "FMS_DB" $connectionString

# Change the app setting for the path to the backups
Set-ApplicationSetting "web.config" "DatabaseBackupRoot" $backupPath

Next I needed to create the property files that represented each environment. The following property file was called Test.ps1.

[string]$connectionString = "Data Source=(local); Database=FMS_TST; Integrated Security=true;"
[string]$backupPath = "c:\data\test"

So now the dev.ps1 script can be called passing in the environment that is being deployed.  In the following example the Test environment is being deployed. 

./dev.ps1 -propertyFile Test

Conclusion

I have shown you a simple way to use powershell to easily configure your application by using property files.  This technique can also be used in the automated build process to set the configuration before running integration tests.  I plan on expanding on this technique and exposing functions to set other frequently used configuration settings (logging details, WCF Endpoints, Other XML configurations).  Powershell is very powerful and makes automating complex tasks easier with less code.  In my command line console applications that performed the same function it would take a lot more lines of code to achieve the same results.