Jimmy Engström

NAVIGATION

Windows phone 8.1 and Bluetooth LE – Getting started

2014-05-04 17:03:00 +0000

With Windows phone 8.1 Microsoft also released the ability to communicate with Bluetooth Low Energy devices.
This is really exciting for Windows phone developers, this way we can start developing apps that can talk to devices without draining the battery dry.

Sadly this is not available in the developer preview of Windows phone 8.1, but will be available when Windows Phone 8.1 is released for general availability.

Pairing

The first step is always to pair with the device you want to connect to.
This is easy to do by going to Settings –> Bluetooth on your phone and tapping on the device you wish to pair with, just as you would do with a  “ordinary” Bluetooth device.

 

Capabilities

To be able to communicate with Bluetooth Low energy (or Bluetooth Smart, as it’s also called) you need to add a capability to your app.
This can’t be done from a GUI, you need to edit the package.appmanifest manually and add the following lines of code just above </Package>.

<Capabilities>
  <m2:DeviceCapability Name="bluetooth.genericAttributeProfile">
    <m2:Device Id="any">
      <m2:Function Type="serviceId:1803"/>
    </m2:Device>
  </m2:DeviceCapability>
</Capabilities>

Now you are are set to start coding =)

 

Iterate through devices

To keep this as simple as possible, I’ll just show you how to iterate through devices and pick up a predefined one.

BluetoothLEDevice currentDevice { get; set; }
string deviceName = "Philips AEA1000";
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    foreach (DeviceInformation di in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelector()))
    {
        BluetoothLEDevice bleDevice = await BluetoothLEDevice.FromIdAsync(di.Id);
        if (bleDevice.Name == deviceName)
        {
            currentDevice = bleDevice;
            break;
        }
    }
}

Find out what your device can do

GATT (Generic Attribute Profile) provides profile discovery and description services for Bluetooth Low Energy protocol, it basically makes it possible to ask your device what it can do. The documentation for this is very thorough and shows how to communicate.

Here is how to get a list of the GATTServices your device supports.

List<string> serviceList = new List<string>();
foreach (var service in currentDevice.GattServices)
{
    switch (service.Uuid.ToString())
    {
        case "00001811-0000-1000-8000-00805f9b34fb":
            serviceList.Add("AlertNotification");
            break;
        case "0000180f-0000-1000-8000-00805f9b34fb":
            serviceList.Add("Battery");
            break;
        case "00001810-0000-1000-8000-00805f9b34fb":
            serviceList.Add("BloodPressure");
            break;
        case "00001805-0000-1000-8000-00805f9b34fb":
            serviceList.Add("CurrentTime");
            break;
        case "00001818-0000-1000-8000-00805f9b34fb":
            serviceList.Add("CyclingPower");
            break;
        case "00001816-0000-1000-8000-00805f9b34fb":
            serviceList.Add("CyclingSpeedAndCadence");
            break;
        case "0000180a-0000-1000-8000-00805f9b34fb":
            serviceList.Add("DeviceInformation");
            break;
        case "00001800-0000-1000-8000-00805f9b34fb":
            serviceList.Add("GenericAccess");
            break;
        case "00001801-0000-1000-8000-00805f9b34fb":
            serviceList.Add("GenericAttribute");
            break;
        case "00001808-0000-1000-8000-00805f9b34fb":
            serviceList.Add("Glucose");
            break;
        case "00001809-0000-1000-8000-00805f9b34fb":
            serviceList.Add("HealthThermometer");
            break;
        case "0000180d-0000-1000-8000-00805f9b34fb":
            serviceList.Add("HeartRate");
            break;
        case "00001812-0000-1000-8000-00805f9b34fb":
            serviceList.Add("HumanInterfaceDevice");
            break;
        case "00001802-0000-1000-8000-00805f9b34fb":
            serviceList.Add("ImmediateAlert");
            break;
        case "00001803-0000-1000-8000-00805f9b34fb":
            serviceList.Add("LinkLoss");
            break;
        case "00001819-0000-1000-8000-00805f9b34fb":
            serviceList.Add("LocationAndNavigation");
            break;
        case "00001807-0000-1000-8000-00805f9b34fb":
            serviceList.Add("NextDstChange");
            break;
        case "0000180e-0000-1000-8000-00805f9b34fb":
            serviceList.Add("PhoneAlertStatus");
            break;
        case "00001806-0000-1000-8000-00805f9b34fb":
            serviceList.Add("ReferenceTimeUpdate");
            break;
        case "00001814-0000-1000-8000-00805f9b34fb":
            serviceList.Add("RunningSpeedAndCadence");
            break;
        case "00001813-0000-1000-8000-00805f9b34fb":
            serviceList.Add("ScanParameters");
            break;
        case "00001804-0000-1000-8000-00805f9b34fb":
            serviceList.Add("TxPower");
            break;
        default:
            break;
    }
}
MessageDialog md = new MessageDialog(String.Join("\r\n", serviceList));
md.ShowAsync();


Time for some fun, Lets make it beep!

In my case I have a Key finder (key fob) and it implements (among other services) the Immediate Alert Service, which makes it possible to make it beep.
The GATT specification shows us how to communicate with the ImmediateAlertService
Download the PDF here.

image


The documentation shows us that if we want to set the alert level we need to do that with “Write without Response”.
The different values for Alert Level can be found here.

Value 0, meaning “No Alert”

Value 1, meaning “Mild Alert”

Value 2, meaning “High Alert”

This snippet will make the key finder (key fob) sound a high alert.

var immediateAlertService = currentDevice.GetGattService(GattServiceUuids.ImmediateAlert);
var characteristics = immediateAlertService.GetCharacteristics(GattCharacteristicUuids.AlertLevel).First();
byte[] data = new byte[1];
data[0] = (byte)2;
await characteristics.WriteValueAsync(data.AsBuffer(), GattWriteOption.WriteWithoutResponse);

 

In my next blog post I will go through more of the things you can do with a key finder (key fob).

Universal apps and NotificationsExtensions - Toasts (Part 3)

2014-04-14 00:50:00 +0000

Here is how to handle toasts the easy way in Universal apps.

First add the “NotificationsExtensions.UniversalApps” Nuget package.

See blog post showing how.

Toast templates:
http://msdn.microsoft.com/en-us/library/windows/apps/hh761494.aspx

It is possible to send any toast template to Windows Phone 8.1 but it will always be shown as an modified version of ToastText02.

You can add a Toast notification like this:

IToastText02 toastContent = ToastContentFactory.CreateToastText02();
toastContent.TextHeading.Text = "Tosty!";
toastContent.TextBodyWrap.Text = "Toasts, best invention since.. ehmm toast";

ScheduledToastNotification toast;
toast = new ScheduledToastNotification(toastContent.GetXml(), DateTime.Now.AddSeconds(10));
toast.Id = "SomeID";
ToastNotificationManager.CreateToastNotifier().AddToSchedule(toast);

Universal apps and NotificationsExtensions - Live Tiles (Part2)

2014-04-14 00:45:00 +0000

Here is how to handle live tiles the easy way in Universal apps.

First add the “NotificationsExtensions.UniversalApps” Nuget package.

See blog post showing how.


Tile templates comparison:
http://msdn.microsoft.com/en-us/library/windows/apps/hh761491.aspx


This is how to update your tile with a scheduled update.

//Create wide tile update
ITileWide310x150Text09 tileContent = TileContentFactory.CreateTileWide310x150Text09();
tileContent.TextHeading.Text = "Wide Tile Text";
tileContent.TextBodyWrap.Text = "More text on the tile";

//Always add a 150x150 tile update also  
ITileSquare150x150Text04 squareContent = TileContentFactory.CreateTileSquare150x150Text04();
squareContent.TextBodyWrap.Text = "More text on the tile";
tileContent.Square150x150Content = squareContent;


ScheduledTileNotification futureTile = new ScheduledTileNotification(tileContent.GetXml(), DateTime.Now.AddSeconds(15));
TileUpdateManager.CreateTileUpdaterForApplication().AddToSchedule(futureTile);

 

To update your tile right away you can use these lines instead of the last two above:

TileNotification tileNotification=new TileNotification(tileContent.GetXml());
TileUpdateManager.CreateTileUpdaterForApplication().Update(tileNotification);

 

Recources

Microsofts code sample:

http://code.msdn.microsoft.com/Alarm-toast-notifications-fe81fc74#content

Nuget version

https://www.nuget.org/packages/NotificationsExtensions.UniversalApps/

Universal apps and NotificationsExtensions (Part 1)

2014-04-14 00:31:00 +0000

 

This is a series of blog posts on how to do notifications in Universal apps.


Managing notifications can be a bit “tricky”, you need to edit xml (or write the xml as a string yourself).
Luckily Microsoft has provided an Universal app project in their sample code that helps with creating notifications, it uses nice interfaces and classes to create the notifications.
I took their help classes from the sample, compiled and uploaded it as a Nuget package to make it simple to do notifications.

Right click on the solution then choose “Manage Nuget packages for solution”

Search for NotificationsExtensions.UniversalApps, press install.

image

You need to make sure you add the package to both the Windows phone and the Windows Store project (you don’t need to add it to the shared project).

To be able to do notifications you also need to enable Toasts, open edit Package.appxmanifest in the Windows phone and Windows 8 project and set Toast capable to “yes”.

image

Now you are good to go!

Microsoft has made the tiles and toast templates available on both platforms (Awesome!), they may look a bit different, see links in each blog post:
Live Tiles

Toasts

 

Recources

Microsofts code sample:

http://code.msdn.microsoft.com/Alarm-toast-notifications-fe81fc74#content

Nuget version

https://www.nuget.org/packages/NotificationsExtensions.UniversalApps/

Download all the videos from Build 2014

2014-04-06 04:51:00 +0000

Build 2014 was packed with announcements and fun stuff.
Still have a lot of videos to watch =)

Here is an updated version of my script I previously blogged about here.

cd "d:\build14"

$pattern = "[{0},\:,\']" -f ([Regex]::Escape([String][System.IO.Path]::GetInvalidPathChars()))             
$pattern
[Environment]::CurrentDirectory=(Get-Location -PSProvider FileSystem).ProviderPath
$a = ([xml](new-object net.webclient).downloadstring("http://s.ch9.ms/Events/Build/2014/RSS/mp4high"))
$a.rss.channel.item | foreach{ 
    $url = New-Object System.Uri($_.enclosure.url)
    $file = [Regex]::Replace($_.Title + " " + $url.Segments[-1] , $pattern, ' ')
    $file
    if (!(test-path $file))
    {
            (New-Object System.Net.WebClient).DownloadFile($url, $file)
    }
}

 

Just copy the code, paste it into a file called “Build2014.ps1”, create a directory (in my case “d:\Build14”) and change the path in the first line of the script.

Right click on the file and choose run with PowerShell.

 

In case you get a problem similar like “Build2014.ps1 cannot be loaded because running scripts is disabled on this system.”

Start PowerShell as an administrator and run “set-executionpolicy unrestricted”, this is probably a bad thing to do for security.