IoT: Ping Pong Scoring via Netduino

Combining InterKnowlogy’s thirst for using the latest and greatest technology with our world famous ping pong skills provides the following result:  during RECESS, I am making a small device that allows us to quickly keep a digital score of our ping pong matches.

Internet of Things (IoT) is a hot topic these days, so I decided to implement the ping pong scoring system on a Netduino board.  I had dabbled with an older board a year or more ago, and was frustrated: one of the first things I wanted to do was make a call to a web API service, but there was no network connectivity.  Enter the newest board, the “Netduino 3 WiFi“.  It has a built-in button and LED, but it’s extensible by way of the 3 GOBUS ports, where you can easily hookup external modules.

Hardware setup

Netduino 3 board with Gobus modules

My shopping list

Required Software

Netduino is a derivative of the Arduino board, with the ability to run .NET Micro Framework (NET MF) code.  This means you get to write your “application” for the board using familiar tools like Visual Studio and .NET.  Here are the steps I went through (loosely following this forum post, but updated to current day):

Network Configuration

This board has WiFi (sweet!), which means you need to get it on your wireless network before you go much further.

Use the .NET Micro Framework Deployment Tool (MFDEPLOY) to configure WiFi on the board.

  • Target, Connect
  • Target, Configuration, Network
  • Set network SSID, encryption settings, network credentials, etc.
  • Reboot the device to take on the new settings!
  • GREEN LIGHT means you’re successfully connected to the network (yellow means it’s searching for a network)

Write Some Code!

After installing the VS plug-in, you now have a new project template.

File, New Project, Micro Framework – Netduino Application (Universal)

Go to the project properties and confirm two things:

  • Application, Target Framework = .NET MF 4.3
  • .NET Micro Framework, Deployment.  Transport = USB, Device = (your device)

On-board light

static OutputPort led = new OutputPort( Pins.ONBOARD_LED, false );
led.Write( true );

On-board button

NOTE: There is a bug with the on-board button in the current Netduino 3 board firmware. While your application is running, pressing the on-board button will cause a reset of the device, not a button press in your application. The work-around until the next version of the firmware is to reference the pin number explicitly, instead of using Pins.ONBOARD_BTN. See my forum post for more information.

static InputPort button = new InputPort( (Cpu.Pin)0x15, false, Port.ResistorMode.Disabled );

GO Button

Now attach a GOBUS button module and the code is a little different.  The Netduino SDK provides classes specific to each module that you use instead of general input / output port classes.

The natural way in .NET to react to button presses is to wire up an event handler.  The GoButton class has such the ButtonPressed event, BUT, there’s a bug in the firmware and SDK:  If you react to a ButtonPressed event and in that handler method (or anywhere in that call stack), you make a call on the network, the call will hang indefinitely.  I discuss this and the work around with others in the a Netduino forum post.

It’s kind of ugly, but instead of wiring up to the events, for now (until the Netduino folks get it fixed), you just sample the IsPressed state of the button in a loop.

Add a reference to Netduino.GoButton.

var goButton = new NetduinoGo.Button();
if ( goButton.IsPressed ) { // do something }

Go Buzzer

Add a reference to Netduino.PiezoBuzzer.

var buzzer = new NetduinoGo.PiezoBuzzer();
buzzer.SetFrequency(noteFrequency);

Talk to the Web!

You bought this board because it has WiFi, so you must want to call a web API or something similar.  In my case, I wrote a simple OWIN based Web API service, hosted in a WPF app that is my ping pong scoreboard display.  This gives me the ability to receive HTTP calls from the Netduino board & client code, straight into the WPF application.

So a call from the Netduino application code to something like http://1.2.3.4:9999/api/Scoring/Increment/1 will give player 1 a point!

I do this using the HttpWebRequest and related classes from the .NET MF.

// error handling code removed for brevity...
var req = WebRequest.Create( url );
req.Timeout = 2000;
using ( var resp = req.GetResponse() )
{
	var httpResp = resp as HttpWebResponse;
	using ( Stream strm = httpResp.GetResponseStream() )
	{
		using ( var rdr = new StreamReader( strm ) )
		{
			string content = rdr.ReadToEnd();
			return content;
		}
	}
}

In my case, the results from my API calls come back as JSON, so I’m using the .NET Micro Framework JSON Serializer and Deserializer (Json.NetMF nuget package).

var result = Json.NETMF.JsonSerializer.DeserializeString( responseText ) as Hashtable;
if ( result != null )
{
    Debug.Print( "Score updated: " + result["Player1Score"] + "-" + result["Player2Score"] );
}

Putting that all together, I have a couple physical buttons I can press, one for each player, and a WPF based scoreboard on the wall that removes any confusion about the score!

Hope you too are having fun with IoT!

 

Unit Testing ASP.NET WebAPI Controllers

Having just written some ASP.NET WebAPI controllers I then needed to accomplish the task of creating Unit Tests for them.  The tests would need to accomplish model validation via DataAnnotation and Json.NET attributes, authentication for all HTTP methods except GET (did I mention IIS was involved here) and in the process exercise an underlying SQL data layer (see UNIT TESTING USING LOCALDB).  I also wanted to write as few Unit Tests as possible and limit mocking but still exercise the whole pipeline.

Some URLs that helped me immensely were:

Some very important things I wanted to accomplish were:

  • Exercise the complete pipeline but without the use of IIS (in any flavor) and without SQLServer (although I guess you could argue that LocalDB is a version of SQLServer)
  • Write the unit tests using code similar to what I would be using in Production code.  This requirement meant I could not use some of the alternate methods for testing Controllers by using a Controller context or special code to make sure DataAnnotation validation was occurring.

The end result eventually boiled down primarily to a single method which makes use of an in memory HttpServer, a reference to the static WebApiConfig class from the Web project containing the controllers and some code to add Basic Auth as needed to the request.  The only configuration necessary in the Unit Test app.config was the <system.web><authentication/></system.web> information necessary to enable authentication and the <connectionString/> section for access to the LocalDB database used in the Unit Tests.

The main method looks like:

    protected static Tuple SendRequest(HttpMethod method, Uri uri, HttpContent content = null, 
	string username = null, string password = null)
    {
	HttpConfiguration config = new HttpConfiguration {IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always};
	// The WebApiConfig class is from the Web project being tested.
	WebApiConfig.Register(config);
	HttpServer server = new HttpServer(config);
	using (HttpMessageInvoker client = new HttpMessageInvoker(server))
	{
	    using (HttpRequestMessage request = new HttpRequestMessage(method, uri.ToString()) { Content = content})
	    {
		if (!string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
		{
		    request.Headers.Add("Authorization",
			"Basic " +
			Convert.ToBase64String(
				Encoding.GetEncoding("iso-8859-1")
					.GetBytes(string.Format("{0}:{1}", username, password))));
		}

		using (HttpResponseMessage response = client.SendAsync(request, CancellationToken.None).Result)
		{
		    return new Tuple(response.StatusCode, response.Content as ObjectContent);
		}
	    }
	}
    }

This allowed me to write fairly simple code in the Unit Tests themselves while still allowing the Unit Test to exercise model validation, authentication, data access layer AND the Controller methods themselves such as:

    [TestMethod]
    [DeploymentItem(@"MyDatabase.mdf")]
    [DeploymentItem(@"MyDatabase_log.ldf")]
    public void GetSingleEntity_That_Does_Not_Exist_Should_Return_NotFound()
    {
	// TestInitialize should have cleared the database.
	Tuple result = SendRequest(HttpMethod.Get, new Uri("http://localhost/api/entity/1"));
	Assert.AreEqual(HttpStatusCode.NotFound, result.Item1);
    }