Accessing the Wifi adapter in the HoloLens

10.06.16   Andres Ayala

Recently I made a HoloLens application that colors the floor of a room according to the WiFi signal strength. Building this app required access to the HoloLens built-in WiFi adapter. However, that task wasn't as straightforward as I had anticipated, since some of the required UWP libraries couldn't be compiled by Unity, and the app needs permission to access the WiFi controller. In this tutorial I will show you how to create a Unity app for HoloLens that can access the WiFi adapter.

Requirements

Create a Unity project

  1. Start Unity.
  2. Select New.
  3. Name your project (e.g. "Wifi Example").
  4. Select 3D.
  5. Select a location to save your project.
  6. Create project.

"Enable Unity Analytics" is optional.

Setup Unity to build for Universal Windows Platform

  1. Go to File > Build Settings...
  2. Select Windows Store from the list.
  3. Select Universal 10 from SDK option.
  4. Select D3D from UWP build type option.
  5. Select Local Machine in Build and Run.
  6. Check Unity C# projects from Debugging group.

We set up Unity to build our project as a Windows store app since HoloLens runs a modified version of Windows based on Universal Windows Platform.

Setup Unity build for HoloLens app development

  1. From Build Settings, open Player Settings...
  2. Select the Windows Store Settings Tab.
  3. Expand "Other Settings."
  4. Check Virtual Reality Supported option from Other Settings group.
  5. Add Windows Holographic from" Virtual Reality SDKs" list.
  6. Expand "Publishing Settings."
  7. Enable InternetClient and InternetClientServer from Capabilities group.

Here you can enable your app to access HoloLens capabilities such as sensors, communication, etc. Unfortunately the WiFi adapter is not included, so we have to manually add it in the Package.appxmanifest later on.

Performance Settings

  1. Open Edit > Project Settings > Quality.
  2. Under "Windows Store" select Fastest from the Default drop-down list.

This is not required but it is recommended so that we can ensure the highest framerate possible.

Setup the Camera

  1. Select Main Camera.
  2. In the Inspector, set the transform position to (0,0,0).
  3. Change the clear flags from skybox to solid color.
  4. Set the background color to absolute Black #00000000.
  5. Set the near value in clipping planes to 0.85.

This settings allow HoloLens to render the background as transparent since HoloLens removes solid black colors from rendering. This also prevents holograms closer than 0.85 meters from being rendered.

Creating an interface for WiFi adapter

We are done setting up our Unity project to be deployed on HoloLens. Now the fun part begins! First we have to create an interface of the desired methods from the WiFi adapter. This interface will help us to decouple the dependency between Unity and UWP libraries that are only accessible on a VS built solution.

  1. Right click in Assets > Create > C# Script
  2. Name it "IWiFiAdapter"

Here is the code for our IWiFiAdapter interface.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace Assets
{
    public interface IWiFiAdapter
    {
        uint GetSignal(string ssid);
        string GetNetworkReport();
    }
}

 

Basically, we want our WiFi adapter to retrieve the WiFi signal of a given Ssid and a Network report of all the networks in range of the adapter.

Now we want to display this information, one easy way is to use Unity Logger to display on console the output values but since we want to test how the signal changes around the access point, we are going to display this information as a hologram using Text UI.

Create a text UI

  1. On the Hierarchy click on Create > UI > Text.
  2. It creates 3 game objects (Canvas, Text and EventSystem), select Canvas.
  3. In the Inspector go to Canvas group and select Screen Space - Camera from Render Mode option.
  4. Drag and drop Main Camera from the hierarchy into Render Camera on the Inspector.

This will bind the Text UI with the main camera, so it will always follow and render in front of the camera. You can edit the attributes of the text game object in the inspector like font, color, size, etc.

Now we need to set the value of the Text UI, for that we are going to add a script to the main camera that is going to call our interface to retrieve the text for the UI.

Displaying the results

  1. Select Main Camera from the hierarchy.
  2. At the bottom of the inspector click Add Component.
  3. Select New Script.
  4. Name it WiFiScanner.
  5. Click on Create and Add.
  6. Double click on the WiFiScanner script.

By default Unity is going to launch Visual Studio with a solution containing all of the project scripts. We can edit, debug our scripts using VS.

The code for WiFiScanner.cs is below.

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System.Net.NetworkInformation;
using System;
using Assets;
 
public class WiFiScanner : MonoBehaviour
{
 
    public Text Display;    // Text UI to display the network information.
    private IWiFiAdapter WiFiAdapter;
    // Use this for initialization
    void Start()
    {
        //WiFiAdapter = new UniversalWiFi();
    }
 
    // This method is being called every frame.
    void Update()
    {
        Scan();
    }
    private void Scan()
    {
        if (WiFiAdapter != null)
        {
            var ssid = "Oshyn-UIO"// The desired SSID to scan.
            var signal = WiFiAdapter.GetSignal(ssid);
            var report = WiFiAdapter.GetNetworkReport();
            Display.text = string.Format("{0} signal:{1}{2}{3}", ssid, signal, Environment.NewLine, report);
        }
    }
}

We declare Display as a Text property of WiFiScanner this object will be the instance of the game object Text UI that we created on Unity Hierarchy.

In order to bind this elements we just have to drag and drop Text into Main Camera's Inspector Display attribute.

Also notice that on Start method we have commented an instantiation of an object of a class named UniversalWiFi this is a class that implements the interface that we previously created. We will uncomment this line after we create UniversalWiFi class on VS.

Build

  1. Open File > Build Settings...
  2. Add Open Scenes.
  3. Click Build.
  4. Choose a folder.

After Unity finishes the build, a file system window will show up. Open the folder that you selected for the build and open the Visual Studio solution file.

We are going to use this solution to deploy our application into HoloLens, but first we need to make a few changes in the Package.appxmanifest to specify the targeted device and also grant access to HoloLens WiFi adapter.

Setting up the project

  1. Expand WiFi Example project.
  2. Right click on Package.appxmanifest.
  3. Select View code.
  4. Find the line TargetDeviceFamily.
  5. Change the attribute Name="Windows.Universal" to Name="Windows.Holographic".
  6. Inside Capabilities add <DeviceCapability Name="wiFiControl" />
  7. Save the changes made in Package.appxmainfest

In Package.appxmainfest you will see that some of the capabilities we specified in Unity were added, but since the WiFiAdapter wasn't an option we needed to manulaly ad this capability as a DeviceCapability on the mainfest.

Now we need to create a class that implements IWiFiAdapter interface.

Assembly-CSharp (Universal Windows) project has the libraries that we need in order to access the WiFi adapter, this is the same for all UWP based OS.

The code for UniversalWiFi.cs is down below.

using Assets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.WiFi;
 
 
namespace Assets
{
    public class UniversalWiFi : IWiFiAdapter
    {
        private bool IsReady { getset; }
        private uint Signal { getset; }
        private string Report { getset; }
        private string Ssid { getset; }
        public UniversalWiFi()
        {
            IsReady = true;
            Signal = 0u;
            Ssid = string.Empty;
            Report = string.Empty;
        }
        public uint GetSignal(string ssid)
        {
            Ssid = ssid;
            Scan();
            return Signal;
        }
 
        private async void Scan()
        {
            if (IsReady)
            {
                IsReady = false;
                uint signal = 0;
                var result = await WiFiAdapter.FindAllAdaptersAsync();
                if (result.Count >= 1)
                {
                    var firstAdapter = result[0];
                    await firstAdapter.ScanAsync();
                    GenerateNetworkReport(firstAdapter.NetworkReport);
                    if (!string.IsNullOrEmpty(Ssid))
                    {
                        signal = GetNetworkSignal(firstAdapter.NetworkReport, Ssid);
                    }
                }
                IsReady = true;
                Signal = signal;
            }
        }
 
        private byte GetNetworkSignal(WiFiNetworkReport report, string ssid)
        {
            var network = report.AvailableNetworks.Where(x => x.Ssid.ToLower() == ssid.ToLower()).FirstOrDefault();
            return network.SignalBars;
        }
 
        private void GenerateNetworkReport(WiFiNetworkReport report)
        {
            var networks = new List<string>();
            foreach (var network in report.AvailableNetworks)
            {
                networks.Add(string.Format("SSID: {0} -- SignalBars: {1} -- Db: {2} -- Mac: {3}",
network.Ssid, network.SignalBars, network.NetworkRssiInDecibelMilliwatts, network.Bssid));
            }
            Report = string.Join(Environment.NewLine, networks.ToArray());
        }
 
        public string GetNetworkReport()
        {
            Scan();
            return Report;
        }
    }
}

 

 

Here we are implementing the IWiFiAdapter interface using WiFiAdapter from Windows.Devices.Wifi. Notice that we are using the same namespace that the interface has.

Don't forget to uncomment in WiFiScanner contructor.

Deploy

  1. Select Assembly-CSharp (Universal Windows) project.
  2. Right click and add a new class.
  3. Name it UniversalWiFi.
  1. In the tool bar select Release as the targeted deploy.
  2. Change ARM to X86.
  3. Click on the arrow next to Local Machine.
  4. Select Remote Machine.
  5. Enter the IP address of your HoloLens device
  6. Select Debug > Start without debugging.

Now the app is deployed wirelessly to HoloLens, you can walk around and will see the changes in the WiFi signal.