Connect SensorTag CC2650 to Azure IOT Hub

I needed to create a demo showing the most simple way to get some sensor data to IOT Hub and I thought sharing the code might be helpful to someone else as well. This app is divided to two parts, first part handling the sensor and second part connecting to IOT Hub.

First we start by creating a new empty UWP app, you can give whatever name you want to it. Because Texas Instrument SensorTag is a bluetooth device, we’ll first initialize the bluetooth connection bits (please note that you need to manually pair the Sensortag in the Windows 10 settings, we’re only dealing here with the code which handles paired devices).

First open the Package.appxmanifest, and in Capabilities tab tick the Bluetooth. Open your Mainpage.xaml.cs file and add the following namespaces:

using Windows.Devices.Bluetooth;
using Windows.Devices.Enumeration;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Storage.Streams;
using Windows.ApplicationModel.Core

We will be needing couple of class members, so let’s add this now:

private BluetoothLEDevice tagDevice;
private GattDeviceService gattDevice;

Next we add the code to find the paired SensorTag device. I placed this code in Mainpage_Loaded override, but you can find more suitable place for it in your code:

foreach (var info in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelector()))
{
    BluetoothLEDevice bleDevice = await BluetoothLEDevice.FromIdAsync(info.Id);
    if (bleDevice.Name.ToLower().Contains("sensortag"))
    {
        tagDevice = bleDevice;
        foreach (var serv in tagDevice.GattServices)
        {
            if (serv.Uuid.ToString() == "f000aa00-0451-4000-b000-000000000000")
            {
                gattDevice = serv;
                break;
            }
        }
        break;
    }
}

The code above first goes through all the BLE devices connected, and then checks for each of them if they have “sensortag” somewhere in their name. This probably finds also first gen sensortags, but you can always make it more specific if needed. After that we’re looking for a certain service with GattService id, which in this case is id for temperature sensor. Sensortag supports other ids/sensors as well, so you can always add more servies, and make a list of the gattDevice instead.

Next step is to start reading the Sensortag itself, and it can be done with the following code:

if (tagDevice != null && gattDevice != null)
{
    // Test connection
    Guid configuration = Guid.Parse("f000aa02-0451-4000-b000-000000000000"); // temperature profile
    var configurationCharacteristics = gattDevice.GetCharacteristics(configuration).First();

    GattCommunicationStatus status = await configurationCharacteristics.WriteValueAsync((new byte[] { 1 }).AsBuffer());

    if (status != GattCommunicationStatus.Success)
    {
        Debug.WriteLine("Connection failed, ensure the SensorTag is powered on");
    }
    else
    {
        // Setup the data read
        Guid data = Guid.Parse("f000aa01-0451-4000-b000-000000000000"); // temperature data
        GattCharacteristic dataCharacteristic = gattDevice.GetCharacteristics(data).First();
        if (dataCharacteristic.CharacteristicProperties == 
            (GattCharacteristicProperties.Read | 
            GattCharacteristicProperties.Notify))
        {
            dataCharacteristic.ValueChanged += this.dataValueChanged;
            status = await dataCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
                GattClientCharacteristicConfigurationDescriptorValue.Notify);

            if (status != GattCommunicationStatus.Success)
            {
                Debug.WriteLine("Sensor access denied");
            }
        }
    }
}

The codeblock above first looks for the temperature service from the gatt device, and tests if the connection can be established and if everything is ok and we can read and get a notify for the data change, we’ll setup a callback function for temperature data. Yet again you can setup multiple callbacks for different sensors by using the GetCharacteristics with different sensor data guids. All that is left is to do the callback method now, which is like this:

private async void dataValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
    GattReadResult readResult = await sender.ReadValueAsync(BluetoothCacheMode.Uncached);
    Color textColor;

    if (readResult.Status == GattCommunicationStatus.Unreachable)
    {
        Debug.WriteLine("Connection lost");
    }

    // Read the sensor value
    var result = new byte[readResult.Value.Length];
    DataReader.FromBuffer(readResult.Value).ReadBytes(result);

    // Extract ambiant temperature
    double ambTemp = BitConverter.ToUInt16(result, 2) / 128.0;

    string data = $"{ambTemp}";

    // Code to send data to IOT Hub
    //TagSensor sensor = new TagSensor() {Temperature = ambTemp};
    //await SendEvent(sensor);

    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
            () =>
            {
                try
                {
                    // This is needed in case you want to update UI with sensor data, temperatureText is a TextBlock
                    //temperatureText.Text = data;
                }
                catch (Exception ex) { }
            });
            
    Debug.WriteLine(data);

}

At this point we are able to read the SensorTag temperature values, and get callback for the changes. Next we’ll add the code required to send this to IOT Hub.

First you should create new IOT Hub in Azure portal, and take note of the Connection String – Primary key (can be found in Shared Access Policies, iothubowner), and copy the value to the connectionString -member variables of the MainPage.xaml.cs and the host name to connectionString2:

// IOT Hub
static RegistryManager registryManager;
static string connectionString = "HostName=XXXXX.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=XXXXXXXXXXXXXXXXXXXXXXXXX";
static string connectionString2 = "XXXXX.azure-devices.net";
static string deviceKey;
private DeviceClient deviceClient;

Add the following Nuget packages to your solution:
– Microsoft.Azure.Devices
– Microsoft.Azure.Devices.Client
and in case it didn’t add automatically, Newtonsoft.JSon as well.

Next you should add the namespaces as well:

using Microsoft.Azure.Devices.Client;
using Microsoft.Azure.Devices;
using Microsoft.Azure.Devices.Common.Exceptions;
using System.Runtime.Serialization.Json;
using System.Threading.Tasks;

Use the latest stable versions of them.

For the device to be able to connect to the IOT Hub you first need to setup the device in the device registry. That can be done with the following code:

private async Task AddDeviceAsync()
{
    registryManager = RegistryManager.CreateFromConnectionString(connectionString);

    string deviceId = "TiTag1";
    Device device = null;
    try
    {
        device = await registryManager.AddDeviceAsync(new Device(deviceId));
    }
    catch (DeviceAlreadyExistsException)
    {
        device = await registryManager.GetDeviceAsync(deviceId);
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message);
    }
    if (device != null)
        deviceKey = device.Authentication.SymmetricKey.PrimaryKey;

}

The device id can be anything you want to give it, in this demo I just simply call it TiTag1.

Next add the call to the method in the beginning of the Mainpage_Loaded (remember to change it to private async void Mainpage_Loaded to be able to call async code inside it):

// Create the IoT Hub Device Client instance
await AddDeviceAsync();
deviceClient = DeviceClient.Create(connectionString2, new DeviceAuthenticationWithRegistrySymmetricKey("TiTag1", deviceKey));

Now is a good time to add a class to represent the sensor, where you can add the other sensors later if you like. Add this before Mainpage class:

public class TagSensor
{
    public TagSensor()
    {
        Time = DateTime.Now;
    }

    public DateTime Time;
    public double Temperature;
}

Next we’ll need to serialize the date to Json, and send to IOT Hub, which can be done like this:

private async Task SendEvent(TagSensor sensor)
{
    var serializer = new DataContractJsonSerializer(typeof(TagSensor));
    var stream = new MemoryStream();
    serializer.WriteObject(stream, sensor);
    string json = Encoding.UTF8.GetString(stream.ToArray(), 0, (int)stream.Length);

    var eventMessage = new Microsoft.Azure.Devices.Client.Message(Encoding.UTF8.GetBytes(json));
    await deviceClient.SendEventAsync(eventMessage);
}

Last piece is to remove the comments in dataValueChanged -method from TiTag Sensor… and async SendEvent -lines and you should be good to go. Please let me know in the comments if you are having issues, always happy to help!

This entry was posted in Uncategorized. Bookmark the permalink.