Creating a Smart Home Device to Track Temperature and Motion

Here’s how to create a simple application using UWP and Windows 10 IoT Core to monitor temperature and track motion.

Windows Developer
Windows Developer
8 min readJan 19, 2018

--

Access to low-cost and energy-efficient computing power is crucial for providing rich functionality when developing for the smart home environment. UWP applications work well for such use cases as they can run on inexpensive computing devices such as the Raspberry Pi.

For instance, here’s how to create a simple application using UWP and Windows 10 IoT Core to monitor temperature and track motion.

Figure 1: The completed application

Reading Data from Sensors in Your IoT Core App

What makes a “smart device” device smart is the ability to read in data from various kinds of sensors — temperature sensors, motion detectors, cameras, etc. and then act upon the information received. Windows 10 IoT Core makes it easy to work with these kinds of sensors and more.

Getting Started with IoT Core Development

To create a UWP application that will run on the Raspberry Pi 2 or 3, you need to create a new Windows Universal application in Visual Studio 2017. For the sake of simplicity, start with a Blank App (Universal Windows) template as shown in Figure 1. Name the project and click OK to create it. If prompted to select a target framework, accept the defaults by clicking OK on that dialog as well.

Figure 2: Creating a Blank Universal Windows project in Visual Studio.

To access the SDKs that enable development for IoT devices, add a reference to the “Windows IoT Extensions for the UWP.” Right mouse click on References in the Solution Explorer for the newly created project. In the following context menu, click on Add Reference to open the Reference Manager as demonstrated above in Figure 2.

Figure 2: Adding a reference to the project.

In the Reference Manager dialog, expand the Universal Windows item and click on Extensions. Look in the list for “Windows IoT Extensions for the UWP.” If there is more than one entry in the list, chose the one with the highest version number as displayed in Figure 3.

Figure 3: Choosing the Windows IoT Extensions for the UWP in the Reference Manager.

Creating the User Interface

Many IoT devices are “headless,” meaning that they have no UI to display. However, for development and testing, it’s always best to have a UI to display information. As both the Raspberry Pi 2 and 3 have HDMI ports, connecting to a display is easy. To create a simple UI for monitoring the IoT device, edit the MainPage.xaml file and add the following XAML code:

This will create a very basic UI that displays the currently reported temperature, motion detector status, and a log of the recent activity seen by the device.

Hardware Initialization

Before the sensors can be used from the IoT device, they first need to be initialized. Initialization is the appropriate time to configure communication protocols and wire up event handlers to the sensor API, as these tasks typically only need to be performed once after the device is powered up.

In the MainPage.xaml.cs file add the following lines of code:

In the MainPage constructor, add the following three lines of code after the call to InitializeComponent(). These methods will perform the initialization for both sensors, as well as a repeating timer, and are explained below:

For temperature readings, a DispatcherTimer will be used to activate at regular intervals to execute code that reads data from the sensor. Since this is a DispatcherTimer instead of a more basic Timer, it will automatically ensure that the timer event is handled by the main GUI thread; this is important since this example code will be updating visual elements such as TextBoxes and TextBlocks.

In the SetupTimer() method below, a DispatcherTimer is created and set to activate once per second (or 1000 milliseconds), and then started:

Next, the temperature sensor needs to be initialized. To read data from the temperature sensor, certain information is needed about the particular sensor being used, such as its clock frequency, mode, and chip select (SS) bus number. In this case, the sensor has a clock frequency of 500,000 and operates in Mode0, and is being used on SS bus 0. Once the settings are configured properly for the sensor, the SPI controller returns a reference to the device (an instance of the SPIDevice class) that can be used to communicate with it:

To communicate with the sensor, byte arrays need to be written and read through the Serial Peripheral Interface (SPI) bus. This communication is done through the SPIDevice object.

The values stored in the writeBuffer byte array will be sent to the sensor and trigger it to deliver a response (in this case, the value [0x01, 0x80, 0x00] is interpreted by the sensor as a request for data). The response will be stored in the readBuffer byte array, which, in this method, is initialized to a default value.

Working with Raw Sensor Data

Every second, the following code will capture the temperature reading and display it on the UI. However, there is more going on deeper in the code:

The ReadTemperatureSensorData() method queries the sensor via SPI by calling the TransferFullDuplex() method on the SPIDevice object with the byte arrays as parameters. The TransferFullDuplex() method allows the controller and the device to communicate simultaneously. This sends the command held in writeBuffer to the sensor, and the sensor responds by writing a byte array back into the readBuffer.

Different kinds of temperature sensors will communicate data with slightly different formats. The ConvertRawDataToInt() method recombines the raw byte values from the sensor into an integer using some bitwise arithmetic:

Using an Event Based Sensor

While temperature readings are meant to be continuous, something event-based like the opening of a door or detection of motion is different. For this project, a Passive InfraRed (PIR) sensor will be used, which will raise an event when it detects motion in the vicinity of a nearby door.

Instead of using the SPI APIs, the motion detector uses the GPIO pins on the Raspberry Pi for communication. GPIO, or General-Purpose Input/Output, uses generic electrical pins on an integrated circuit or board whose behavior is manageable by code at run time.

While GPIO and SPI work differently from each other, they are alike in that both still need to be initialized before use. To initialize the motion sensor on GPIO, the corresponding pin needs to be identified and configured.

IoT devices often have dozens of available GPIO pins; this example assumes that pin #5 is being used to communicate with the motion sensor. Because this pin is being used for input (GPIO pins can also be used to send data as output), the Drive Mode also needs to be configured for GpioPinDriveMode.Input.

This SetupMotionSensor() method in MainPage.cs initializes the GPIO pin and then adds an event handler that will trigger when a voltage change is detected on the pin (usually 5v or 3v for a “high” value, and 0v for a “low” value):

All that’s left to do now is add code to handle the detection of a signal on the motion sensor pin, and update the UI when motion is detected:

private void PirSensorPin_ValueChanged (GpioPin sender, GpioPinValueChangedEventArgs e)

To be noted, that this sensor is of the “active low” variety, which means that when motion is detected, it will drop the voltage on its signal line to 0v. And while motion is not detected, it will hold it at “high” (5v or 3v). Other sensors will behave oppositely (classified as “active high” devices). This is an important distinction to make, because it impacts how the motion events are interpreted.

Since this is an “active low” sensor, the voltage will fall as soon as the event begins, and it will rise back to a “high” state once the event has ended. These voltage transitions are known as edges, and thus a signal transitioning from “high” to “low” is said to be experiencing a “falling edge”, and a signal transitioning from “low” to “high” is said to be in the “rising edge” state. Therefore, at the moment the sensor detects motion, it will report a “falling edge” during the corresponding ValueChanged event. This is why the PirSensorPin_ValueChanged() event handler checks for GpioPinEdge.FallingEdge when detecting motion events.

Digging Deeper

This is only an introduction to creating a smart home device with the UWP. Windows developers can leverage much of their existing skills to build solutions that run on any number of devices with ease. The Windows IoT Core extension enables interaction directly with hardware either through the abstraction of the SPI bus or directly reading and manipulating voltage signals on the circuit board.

Learn more here!

--

--

Windows Developer
Windows Developer

Everything you need to know to develop great apps, games and other experiences for Windows.