Bardaan A
Published © GPL3+

003b - Raspberry Pi 2B with FezHat Sensors and Azure IoT Hub

This is a supplementary tutorial to the 003 tutorial. In this tutorial we'll develop a program to collect and upload the FezHat sensor data.

AdvancedFull instructions provided10 hours939
003b - Raspberry Pi 2B with FezHat Sensors and Azure IoT Hub

Things used in this project

Hardware components

Raspberry Pi 2 Model B
Raspberry Pi 2 Model B
×1
FezHat
×1

Software apps and online services

Visual Studio 2015
Microsoft Visual Studio 2015
Microsoft Azure
Microsoft Azure

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Code

IoTHub.cs

C#
This class contains methods that converts the SensorData type into JSON and deliver it to the IoT Hub.
////The MIT License(MIT)
////Copyright(c) 2016 BardaanA

////Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

////The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

////THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Azure.Devices;
using Microsoft.Azure.Devices.Client;
using Newtonsoft.Json;
//using System.Diagnostics;

namespace RasPi2BApp
{
    class IoTHub
    {
        // Standard IoT Hub device client and message
        private DeviceClient device;
        private Microsoft.Azure.Devices.Client.Message payload;
        string payloadIntoString;
        private bool initialized;
        public bool IsInitialized { get { return initialized; } }

        public void Initialize(string iotHubHostName,string deviceKey,string deviceId)
        {
            initialized = false;
            try
            {
                // Simply WOW! Good job microsoft Azure/IoT team... Thanks!
                device = DeviceClient.Create(iotHubHostName,new DeviceAuthenticationWithRegistrySymmetricKey(deviceId,deviceKey),Microsoft.Azure.Devices.Client.TransportType.Http1);
                if(device != null)
                {
                    initialized = true;
                }
            }
            catch(Exception ex)
            {
                //Debug.WriteLine("IoT Hub initialization failed!  " + ex.Message);
                throw new SensorException(ex.Message);
            }
        }

        // So this is where all the magic happens, the payload is "Spirited Away"!
        public async Task Upload(SensorData gpsData)
        {
            try
            {
                // JSON! JSON! JSON!
                payloadIntoString = JsonConvert.SerializeObject(gpsData);
                payload = new Microsoft.Azure.Devices.Client.Message(Encoding.UTF8.GetBytes(payloadIntoString));
                await device.SendEventAsync(payload);
            }
            catch(Exception ex)
            {
                //Debug.WriteLine("Upload failed!  " + ex.Message); // Seriously!
                throw new SensorException(ex.Message);
            }
        }

        public async Task Close()
        {
            await device.CloseAsync();
            device.Dispose();
        }
    }
}

MainPage.xaml.cs

C#
This is the code behind file for the Main interface for the UWP app. This is the where the main program enters execution. Here we hace setup a timer which ticks every 30 seconds and collects sensor data and uploads the payload.
////The MIT License(MIT)
////Copyright(c) 2016 BardaanA

////Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

////The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

////THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;


// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace RasPi2BApp
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    /// 

    // In this UWP Application we'll be collecting some sensor data from the FezHat every 30 seconds, convert that data into JSON
    // and upload it to Azure IoT Hub for further processing and Storage.
    public sealed partial class MainPage : Page
    {
        // This is the IoT Hub's Hostname it can be retrieved from the Azure Portal
        private string iotHubHostname = "...";
        // This is the name of the device that we created, when we registered our device to the IoT Hub
        // Registry
        private string deviceName = "...";
        // This is the device Key that was generated when we registerd our device into the registry
        // This can also be retrieved from the Azure Portal
        private string deviceKey = "...";

        // Containment and Delegation once again
        // An IoTHub object
        private IoTHub iotHub;
        // Our Main timer, this timer is going to dictate the program flow and sends device data in 30 second intervals
        private DispatcherTimer mainTimer;
        // SensorData object reference
        private SensorData sensorData;
        // Sensors object reference
        private Sensors sensors;

        public MainPage()
        {
            // This is where all the UWP elements are initialized... Kind of mandatory!
            this.InitializeComponent();

            // Setup all the necessary resources and initialize them            
            SetupSensors();
            SetupIoTHub();
            SetupTimer();
        }

        // This is where all the action is. This method is called every 30 seconds
        // by the DispatcherTimer
        private async void OnMainTimerTick(object sender,object e)
        {
            try
            {
                // This is where the sensor data is collected in to the SensorData type
                if(sensors.IsInitialized)
                {
                    textBlockSensorStatusStatus.Text = "Initialized";
                    textBoxPayloadDeliveryStatus.Text = "...";
                    sensorData = sensors.Read();
                    textBoxSensorValue.Text = sensorData.ToString();
                    if(iotHub.IsInitialized)
                    {
                        textBlockIoTHubStatusStatus.Text = "Initialized";
                        // Now this is where our data, in this case it is SensorData is passed on to be packaged in to JSON payload and finally
                        // uploaded to the IoT Hub. In a way our data is being, "Spirited away!"
                        await iotHub.Upload(sensorData);
                        textBoxPayloadDeliveryStatus.Text = "Successfully delivered!";
                    }
                    else
                    {
                        textBlockIoTHubStatusStatus.Text = "Not Initialized";
                        textBoxPayloadDeliveryStatus.Text = "...";
                    }
                }
                else
                {
                    textBlockSensorStatusStatus.Text = "Not Initialized";
                }
            }
            catch(Exception ex)  // Please no!!!!
            {
                throw new SensorException(ex.Message);
            }
        }

        // This is where we setup our timer
        private void SetupTimer()
        {
            mainTimer = new DispatcherTimer();
            mainTimer.Interval = TimeSpan.FromMilliseconds(30000); // 30 second intervals
            mainTimer.Tick += OnMainTimerTick;
            Task.Delay(60000);  // Give some time for the Sensors to warm up
            mainTimer.Start();  // Ready set go...
        }

        // This is where the IoT Hub object is initialized. The security access strings are
        // passed in here
        private void SetupIoTHub()
        {
            iotHub = new IoTHub();
            iotHub.Initialize(iotHubHostname,deviceKey,deviceName);
        }

        // This is where we setup out FezHat and initialize out SensorData type
        private async void SetupSensors()
        {
            sensorData = new SensorData();
            sensors = new Sensors();
            await sensors.Initialize();
        }

        private async void buttonClose_Click(object sender,RoutedEventArgs e)
        {
            mainTimer.Stop();
            await iotHub.Close();
        }
    }
}

MainPage.xaml

XML
This is the design code in XAML for the user interface.
<Page
    x:Class="RasPi2BApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:RasPi2BApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="#FF81CCFF">
        <TextBlock x:Name="textBlockSensorStatus" HorizontalAlignment="Left" Margin="38,47,0,0" TextWrapping="Wrap" Text="Sensor Status: " VerticalAlignment="Top" Width="251" Height="53" FontSize="36"/>
        <TextBlock x:Name="textBlockSensorStatusStatus" HorizontalAlignment="Left" Margin="356,47,0,0" TextWrapping="Wrap" Text="..." VerticalAlignment="Top" Width="618" Height="53" FontSize="36"/>
        <TextBox x:Name="textBoxSensorValue" HorizontalAlignment="Left" Margin="38,119,0,0" TextWrapping="Wrap" Text="..." VerticalAlignment="Top" Width="936" Height="213" FontSize="22"/>
        <TextBlock x:Name="textBlockIoTStatus" HorizontalAlignment="Left" Margin="38,368,0,0" TextWrapping="Wrap" Text="IoT Hub Status: " VerticalAlignment="Top" Width="276" Height="53" FontSize="36"/>
        <TextBlock x:Name="textBlockIoTHubStatusStatus" HorizontalAlignment="Left" Margin="356,368,0,0" TextWrapping="Wrap" Text="..." VerticalAlignment="Top" Width="618" Height="53" FontSize="36"/>
        <TextBox x:Name="textBoxPayloadDeliveryStatus" HorizontalAlignment="Left" Margin="38,446,0,0" TextWrapping="Wrap" Text="..." VerticalAlignment="Top" Width="936" Height="65" FontSize="36"/>
        <Button x:Name="buttonClose" Content="Close" HorizontalAlignment="Left" Margin="680,609,0,0" VerticalAlignment="Top" Height="114" Width="294" FontSize="72" Background="#FFB80000" Foreground="White" Click="buttonClose_Click"/>

    </Grid>
</Page>

SensorData.cs

C#
This is a SensorData type. We collect all the sensor data from the FezHat and package it into this data type, for easier handling and delivery.
////The MIT License(MIT)
////Copyright(c) 2016 BardaanA

////Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

////The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

////THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RasPi2BApp
{
    // Sensor data type from FEZ HAT is packaged into this form for easy transport.
    // Note the to string method at the bottom, isn't that beautiful?!
    class SensorData
    {
        public double Temperature { get; set; }
        public double LightLevel { get; set; }
        public double AnalogInOne { get; set; }
        public double AnalogInTwo { get; set; }
        public double AnalogInThree { get; set; }
        public double ServoOne { get; set; }
        public double ServoTwo { get; set; }

        public SensorData()
        {
            Temperature = 0;
            LightLevel = 0;
            AnalogInOne = 0;
            AnalogInTwo = 0;
            AnalogInThree = 0;
            ServoOne = 0;
            ServoTwo = 0;
        }

        public override string ToString()
        {
            return $"Sensors:: Temperature: {Temperature}, Light Level: {LightLevel}, Servo One: {ServoOne}, Servo Two: {ServoTwo}, Analog One: {AnalogInOne}, Analog Two: {AnalogInTwo}, Analog Three: {AnalogInThree}";
        }
    }
}

SensorException.cs

C#
This defines a custon sensor exception. Comes in handy when dealing with exceptions.
////The MIT License(MIT)
////Copyright(c) 2016 BardaanA

////Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

////The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

////THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RasPi2BApp
{
    // Just following the exceptional convention ;)
    class SensorException : Exception
    {
        private string message;

        public SensorException(string msg)
        {
            message = msg;
        }

        public override string Message
        {
            get
            {
                return $"Sensor fail! "+ message + " " + base.Message;
            }
        }
    }
}

Sensors.cs

C#
This class contains methods to collect sensor data from FezHat and package it into our custom SensorData type.
////The MIT License(MIT)
////Copyright(c) 2016 BardaanA

////Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

////The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

////THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

// Library used to access the FEZ HAT
using GHIElectronics.UWP.Shields;
//using System.Diagnostics;

namespace RasPi2BApp
{
    class Sensors
    {
        // Containment delegation, anyone?? LOL!
        private FEZHAT hat;
        private SensorData sensorData;

        // Initialization test flag
        private bool initialized;
        public bool IsInitialized { get { return initialized; } }

        public async Task Initialize()
        {
            initialized = false;
            try
            {
                hat = await FEZHAT.CreateAsync();
            }
            catch(Exception ex)
            {
                //Debug.WriteLine("FezHat initialization failed! " + ex.Message);
                throw new SensorException(ex.Message);
            }

            if(hat != null)
            {
                initialized = true;
                // You might wanna change these values to prevent your servos from grinning!
                // We don't have any replacement to ship to you guys. But we do know where to get them, ebay??
                hat.S1.SetLimits(500,2200,0,180);
                hat.S2.SetLimits(500,2200,0,180);
                // Start position
                hat.S1.Position = 90;
                hat.S2.Position = 90;
            }
        }

        // Read the sensor data, for updated values.
        public SensorData Read()
        {
            sensorData = new SensorData();
            if(this.hat != null)
            {
                try
                {
                    sensorData.Temperature = Celsius2Fahrenheit(hat.GetTemperature());
                    sensorData.LightLevel = hat.GetLightLevel();
                    sensorData.AnalogInOne = hat.ReadAnalog(FEZHAT.AnalogPin.Ain1);
                    sensorData.AnalogInTwo = hat.ReadAnalog(FEZHAT.AnalogPin.Ain2);
                    sensorData.AnalogInThree = hat.ReadAnalog(FEZHAT.AnalogPin.Ain3);
                    sensorData.ServoOne = hat.S1.Position;
                    sensorData.ServoTwo = hat.S2.Position;
                }
                catch(Exception ex)
                {
                    //Debug.WriteLine("Sensor data read failed! " + ex.Message);
                    throw new SensorException(ex.Message);
                }
            }
            // I have been using this querky method of initializing objects to zero, just to avoid errors.
            // You are welcome to use a better design pattern
            return sensorData;
        }

        // Servo control method, takes a double array as an input
        public void ServoControl(double[] inputArray)
        {
            if(hat != null)
            {
                hat.S1.Position = inputArray[0];
                hat.S2.Position = inputArray[1];
            }
        }

        // Method to convert Celsius to Fahrenheit because FezHat returns temperature value in Celsius
        private double Celsius2Fahrenheit(double input)
        {
            return ((input * 9.0) / 5.0) + 32.0;
        }
    }
}

Credits

Bardaan A

Bardaan A

8 projects • 16 followers
Just another Software and Technology enthusiast.
Thanks to Microsoft.

Comments