[Domotica | Win IoT | .NET Core 2.1] MVC Web SignalR Hub

Ok, so I have a working application on my RPi to communicate with the z-stick.

The next step would be to replace the simple loop on/off test with an actual interface with some switches to turn adapter on and off. At first I had the idea to go for a simple web api. From there I would create a web interface to send command to the web api which would pass the command to the z-stick. The issue I was facing with this solution is that when there are multiple interfaces open (my wife’s phone, my phone and perhaps some general device hanging on the wall), I can only update the interface of the current user when a switches has been pressed, unless I would use a polling mechanism to the web api endpoint and continuously check the state of the adapter. I absolutely do not prefer this solution because of the possible load I might generate in the endpoint (and let’s be honest, checking every second for a state which only changes once in a while is sort of a DDos attack on your own environment).

While I was searching the internet for how to deal with this scenario, I came across a Youtube post of Hassan Rage. In this video he shows a really simple example of using SignalR for communication between his RPi and his switch. As SignalR provides a real time connection between the host and multiple devices and as of the solution works very well in the video, I decided to use this option as well.

Setting up the SignalR Hub
I am not getting into the details of how to setup SignalR, but if you are unfamiliar with this you can start checking out this page which can explain how it works and how to get this into your project.

I am adding a new ASP.NET Core 2.1 Web API application to my current project to start with. After adding SignalR to my project I am ready to set up my Hub.

Important to understand is that SignalR is based on sending and receiving data. As the SignalR Hub will be the host, the UWP app will be a client connected to the Hub. The web interface (which contains the actual switches to press) will also be a client of the Hub. Once a switch is tapped, it will pass the command to the Hub. The Hub broadcasts the command to all connected clients including the UWP app. Once the UWP app has triggered the node on the z-stick it will return an executed command back to the Hub. This command is also broadcasted to all connected clients which will be picked up by the web interface and results in toggling the switch on multiple devices.

To make the story above possible I need to have 2 methods in my Hub; Switch and SwitchExecuted:

        public void Switch(string data)
        {
            Clients.All.SendAsync("ExecuteSwitch", data);
        }

        public void SwitchExecuted(string state, byte nodeId)
        { 
            Clients.All.SendAsync("SwitchExecuted", state, nodeId);
        }

data  is the Switch method is a serialized JSON set containing the new state and the node, which is the same for the SwitchExecuted method.

In order to handle this message and to reply with a SwitchExecuted message I need to change my UWP app a bit.

        public void RegisterSignalRCalls()
        {
            _signalRHost.On<string>("ExecuteSwitch", async (data) =>
            {
                var cmd = JsonConvert.DeserializeObject<SwitchCommand>(data);
                await SwitchBinary(cmd.State, cmd.Node);
            });
        }
        
        public async Task SwitchBinary(bool turnOn, byte nodeId)
        {
            var currentNode = _zWaveController.GetNodes().Result[nodeId];
            var switchBinary = new SwitchBinary(currentNode);
            await switchBinary.Set(turnOn);

            await _signalRHost.InvokeAsync("SwitchExecuted", state.ToString(), nodeId);
        }

And that is all to it. A test can be made easily with a Console application, hook it up on the Hub and send the switch command. You can deploy the application to Azure or simply run in on your own machine. By doing this, don’t forget to include the correct Url referring to the Hub in the UWP app.

        void EstablishConnectionSignalRHost()
        {
            var hubConn = new HubConnectionBuilder()
                            .WithUrl("http://[YourLinkHere]/[NameOfYourHub]")
                            .Build();

            new Adapters(_controller, hubConn).RegisterSignalRCalls();

            hubConn.StartAsync();
        }

I will go deeper in the web UI in the next article where I will use jQuery, HTML5 and CCS3 to create some switches.

Leave a Reply

Your email address will not be published. Required fields are marked *