In a previous post a .Net Standard library that can be used in .Net Core, .Net Standard, UWP and Xamarin apps (last yet to be tested) was presented that implements the device and service functionality of IoT Hub Device Streaming that can be used in UWP and other types apps. The previous blog exemplified the use of the library through a UWP-XAML test app. This blog discusses the use of the library’s API from a programmatic perspective.

API calls for Default functionality

In this mode the device and server operate in single shot mode. That is the device listens for a connection vi IoT Hub, receives the message, processes it and sends it back. The service connects to the device via the same Iot Hub, sends it message then awaits the reply. A socket it created at each end only for the duration of each communication.

Calls are made to the DeviceStream_Device, DeviceStream_Service and DeviceStreamingCommon classes in the library. All of the Azure IoT Hub Device Streaming functionality, as in these classes in the IoT Hub SDK Echo sample, has been refactored (and extended) into these classes in the library. Where there is app specific functionality required by the classes, a delegate is used.

In default node, the code required to set the device to listen for one connection follows

Device App calls to the library

The call to set the device in one shot listen mode is quite simple:

private async void Button_Click_Device(object sender, RoutedEventArgs e)
{
    DeviceStreamingCommon._Timeout = TimeSpan.FromMilliseconds(10000);//10 seconds
    string device_cs ="Device connection string"
    await Task.Run(() =>
    {
        DeviceStream_Device.RunDevice(device_cs, OnDeviceRecvText).GetAwaiter().GetResult();
    });
}

The call requires a delegate OnRecvText which can be null, but there would be no point to that. A sample method that implements a simple handling of the received message (uppercasing it) follows:

private string OnDeviceRecvText(string msgIn)
{
    Console.WriteLine(msgIn);
    string msgOut = msgIn.ToUpper();
    Console.WriteLine(msgOut);
    return msgOut;
}

Service App calls to the API

The call in the service app to send one message and get the response follows:

private async void Button_Click_Svc(object sender, RoutedEventArgs e)
{
    DeviceStreamingCommon._Timeout = TimeSpan.FromMilliseconds(10000);
    service_cs ="IOT Hub connection string";
    device_id ="Device Id"; //Eg "MyDevice"
    string msgOut = "Hello Azure";
    await Task.Run(() =>
    {
        DeviceStream_Svc.RunSvc(service_cs, device_id, msgOut, OnSvcRecvText).GetAwaiter().GetResult();
    });
}

This also requires a delegate to handle the reply:

private static void OnSvcRecvText(string msg)
{
    Console.WriteLine(msg);
}

That’s all that is required in One Shot mode.

Note that in the sample apps, this code is with in multiple targeted try-catch constructs so a to identify any issues. The library code has similar checks and balances.

To change what the device (which is typically an IoT device) does, you only need to modify OnDeviceRecvText()in the device app. This could for example, read some sensor values and return them.

API calls to make use of the options

These options are are implemented by adding delegates to RunDevice() and RunSvc() calls, which by default are taken as being null and therefore not called in Single-Shot mode.

Keep Alive

The sockets at both end can be kept alive between messages until the user end signals otherwise. This requires another delegate to be implemented in the device app and a modification to the OnDeviceRecvText() method. The API has been constructed so that the user service app dictates if the connection is to be kept alive and therefore the message it sends needs to have embedded in it a flag to indicate this. The device message reception, OnDeviceRecvText() needs to mirror this and decipher if the connection is to be kept alive. The additional delegate, GetKeepAlive(), just returns this when called by the DeviceStream_Device at the end of its message processing.

The Device

private async void Button_Click_Device(object sender, RoutedEventArgs e)
{
    DeviceStreamingCommon._Timeout = TimeSpan.FromMilliseconds(10000);//10 seconds
    string device_cs ="Device connection string"
    await Task.Run(() =>
    {
        DeviceStream_Device.RunDevice(device_cs, OnDeviceRecvText,GetKeepAlive).GetAwaiter().GetResult();
    });
}

private bool keepAlive=false;
public bool GetKeepAlive()
{ return keepAlive; }

An example of passing a “flag” from the service to the device is prepend an indicative character, in this case ‘`’. If present in a message received by the device, flag it then remove.

private char keepAliveChar = '`';
private string OnDeviceRecvText(string msgIn)
{
    if (msgIn.ToLower()[0] == keepAliveChar)
    {
        keepAlive = true;
        msgIn = msgIn.Substring(1);
    }
    else 
        keepAlive = false;
    Console.WriteLine(msgIn);
    string msgOut = msgIn.ToUpper();
    Console.WriteLine(msgOut);
    return msgOut;
}

The Service

private async void Button_Click_Svc(object sender, RoutedEventArgs e)
{
    DeviceStreamingCommon._Timeout = TimeSpan.FromMilliseconds(10000);
    service_cs ="IOT Hub connection string";
    device_id ="Device Id"; //Eg "MyDevice"
    string msgOut = "Hello Azure";
    bool KeepAlive = true; //eg Get from UI Checkbox
    msgOut = ProcessMsgOut(msgOut, KeepAlive);
    await Task.Run(() =>
    {
        DeviceStream_Svc.RunSvc(service_cs, device_id, msgOut, OnSvcRecvText,GetKeepAlive).GetAwaiter().GetResult();
    });
}

private bool keepAlive=false;
public bool GetKeepAlive()
{ return keepAlive; }

Just prepend the keepAliveChar if KeepAlive is required:

private char keepAliveChar = '`';
private string ProcessMsgOut(string msg, bool keepAlive)
{
    if (keepAlive)
        msg = keepAliveChar + msg;
    return msg
}

MORE To Follow





 TopicSubtopic
<  Prev:    
This Category:Azure
<  Prev: