Feiko.IO

WebSocket Server for .NET nanoFramework

Having fun with websockets

Friday, 18 February 202217 min read
image

It’s been a little quite on my website lately. For good reasons. Last month’s I’ve been hard at work getting the nanoFramework library ready for release. In This blog I want to show how easy it is to get started with websockets on .NET nanoFramework. The blog goes together with a video I made demonstrating websockets for the Microsoft Internet of Things Show.

What are websockets and why should you care about running websockets on tiny IoT devices?

Websockets is a web protocol that uses a normal HTTP request and strips away all the HTTP stuff so it has direct access to the underlying TCP Socket. This way the server client connections stays open and the server can continuously send information to the client and the other way around. This opposed to normal HTTP requests where a client asks for some information and gets a reply after which the connection is usually closed. Imagine you have a webpage or a WebApp that you constantly want to update with new information. Then you want to be using websockets. Websockets are used more often on the World Wide Web than you might think. Every time you open a page in your browser and a chat bot starts a live conversation. You know this webpage is using websockets.

Now, why do you want to have websockets on tiny microcontrollers? Well imagine you have a small weather station on the roof of your house and you want to be able to monitor the wind in real-time. Having this weather station run a small websocket server is a great way of doing this. Having a real-time graph that updates every second or even less, is not a problem for websockets! Of course you can also use other techniques like MQTT or a direct TCP connection. But this requires your user to install some kind of app on there device. When using websockets you can use any device with a web browser to connect to your device without the need of installing any apps. It’s easy and it bring so much more fun to your IoT projects!

How to get started with .NET nanoFramework and websockets?

As always, the Websocket library it's open source on Github together with all the documentation and links to some sample projects. I’ve gone through the trouble of creating a websocket client as well as a websocket server implementation. For this blog we’ll be looking into the first sample Server.RgbSample using the nanoFramework WebSocket Server.

In this example we are going to control the RGB led of an ATOM Lite ESP32 microcontroller device from M5Stack. The ATOM Lite is a great little and very cheap device with a RGB Led, a programable button and some extra IO’s. If you don’t own a ATOM Lite you can probably just use any ESP32, of course this is less fun 😉.

The Code

You can grab the code for the WebSockets.Server.RgbSample sample by cloning the complete Samples Git repo or download a zip copy from GitHub. Go to the .\Samples\samples\Websockets\WebSockets.Server.RgbSample directory and open the NFWebSockets.Server.RgbExample.sln file with Visual Studio. If you want to run the code make sure you update all the NuGet packages to the latest preview versions. If you want to create your own websocket solution you can simply reference the nanoFramework.System.Net.WebSockets.Server NuGet package.

If you're new to nanoFramework, or run into trouble you can watch this video I've created on how to get started. You'll be up and running in now time!

Yes you made it. Now it's time to get started with websockets, it's easy. Creating and starting the websocket server is done with the following code.

_wsServer = new WebSocketServer(new WebSocketServerOptions()
    {
        MaxClients = 10,
        IsStandAlone = false
    });


_wsServer.MessageReceived += WsServer_MessageReceived;
_wsServer.Start();

As you can see you can use the optional WebSocketServerOptions to set some extra options. It’s good practice to set a max number of websocket clients. This will make sure you don’t run out of resources. Remember it’s still only a small microcontroller with a few hundred kB of RAM.

By default, the websocket server will run as a standalone server hosted on port 80. Because we are also going to host our own WebApp we want to have it integrated with a webserver. To be able to do this I’ve set the IsStandAlone option to false. Before we start the server we attach an event handler to the MessageReceived event. This event handler is called whenever there is an incoming websocket message from a client, this is where all the magic happens.

private static void WsServer_MessageReceived(object sender, MessageReceivedEventArgs e)
{
    var wsServer = (WebSocketServer)sender;
    if (e.Frame.MessageType == WebSocketMessageType.Binary && e.Frame.MessageLength == 3)
    {
        AtomLite.NeoPixel.SetColor(Color.FromArgb(e.Frame.Buffer[0], e.Frame.Buffer[1], e.Frame.Buffer[2]));
        wsServer.BroadCast(e.Frame.Buffer);
    }
}

Here we see that the server is expecting the RGB color to be send as an array of three bytes. For every color one byte: Red Green and Blue. This color is send to the LED of the device and then send to all connected clients.

*Note: If you like you can of course also specify the client you want to send the information to. To monitor the connected clients you can use WebSocketOpened and WebSocketClosed event which will provide the EndPoint of the client that is used as an identifier for the websockets. Listclients will provide you with a list of endpoints of all connected clients.*

Finally the code below shows how to handover a websocket request from the Webserver to the Websocket Server.

//webserver receive message
private static void WebServer_CommandReceived(object obj, WebServerEventArgs e)
{
    //check the path of the request
    if (e.Context.Request.RawUrl == "/")
    {
        //check if this is a websocket request or a page request 
        if (e.Context.Request.Headers\["Upgrade"] == "websocket")
        {
            //Upgrade to a websocket
            _wsServer.AddWebSocket(e.Context);
        }
        else
        {
            //Return the WebApp
            e.Context.Response.ContentType = "text/html";
            e.Context.Response.ContentLength64 = html.Length;
            WebServer.OutPutStream(e.Context.Response, html);
        }
    }
    else
    {
        //Send Page not Found
        e.Context.Response.StatusCode = 404;
        WebServer.OutPutStream(e.Context.Response, "Page not Found!");
    }
}

Here we check if a request it's a Websocket request by checking the Upgrade header. If it is, we just handover it over to the webrequest context of the webserver using _wsServer.AddWebSocket(e.Context). And the webserver will work its magic. If the request is a regular web request we’ll return the WebApp. And that’s everything.

*Note: If you want to keep track of specific websocket users, you can use a custom header that you read using the webserver before you handover the request context. The request also contains the unique IPEndpoint that’s used by the webserver. This is one way to keep track of your clients.*

Run the solution

After you changed the WiFi Ssid and Password in the code you’re ready to fire everything up and see what happens. In the debug output you’ll find the URL to connect to the device. Make sure you’re on the same network as the device.

Open up a browser and connect to the device using the URL or the IP address of the device. In the app you can pick a color. You'll notice that's very responsive. You can even drag over the color picker and the colors will change instantly. Now the background is the color that’s broadcasted to all connected clients. So let’s make it interesting and open up some extra browser tabs. Now if you run these tabs side by side you can see background color on all browser windows are changing in real-time. This is something you can’t achieve with normal HTTP requests!

Note: If you run the device without the debugger attached you can get even higher websocket throughput speeds.*

Final thoughts

By experimenting with this demo you're probably imagining how easy and fun it would be to create an app that would constantly output sensor data i.e. for a wind speed meter. I hope you learned how easy and awesome it is to create a websocket server. Please let me know what you’re going to build using websockets. Have fun!