Jimmy Engström

NAVIGATION - SEARCH

Universal apps and Bluetooth LE – Battery Service

Some devices exposes a battery service that can supply us with the current (no pun intended) battery level.
I started this blog series working with only Windows phone in mind, but then I realized if it is possible to achieve the same results with an universal app of course that’s the route I should take.

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>.
Don’t forget to do that in both your Windows 8 and Windows Phone projects.

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

Now you are are all set to start coding =)

 

Battery Level Service

The battery service must implement read, and notify is optional.
What that means is that you can always assume that you will be able to read the battery level (if your device implements the battery service, but you have to check if it supports Notify  (a good developer should always check Ler med tungan ute ).

image

The value it returns is a byte with a value from 0 to 100 representing a percentage of the current charge (0 being fully discharged).

The property

This is just a standard property with a backing store.

 private int _BatteryLevel;
        public int BatteryLevel
        {
            get
            {
                return _BatteryLevel;
            }
            set
            {
                _BatteryLevel = value;
                OnPropertyChanged();
            }
        }

The interesting part is how we handle OnPropertyChanged to try to avoid “The application called an interface that was marshalled for a different thread”.
I found a very neat piece of code here.


My implementation looks like this:

        public event PropertyChangedEventHandler PropertyChanged;

        private readonly CoreDispatcher _dispatcher;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            if (_dispatcher == null || _dispatcher.HasThreadAccess)
            {
                var eventHandler = this.PropertyChanged;
                if (eventHandler != null)
                {
                    eventHandler(this,
                        new PropertyChangedEventArgs(propertyName));
                }
            }
            else
            {
                IAsyncAction doNotAwait =
                    _dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                    () => OnPropertyChanged(propertyName));
            }
        }

 

 public BatteryServicePage()
        {
            if (!DesignMode.DesignModeEnabled)
            {
                _dispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
            }
          ........
        }


Reading a value

I have written a simple method that reads a value from the service and if it supports notification it will also start a subscription on those notifications.

 public async Task<byte[]> GetValue(Guid gattCharacteristicUuids)
        {
            try
            {
                var gattDeviceService = await GattDeviceService.FromIdAsync(Device.Id);
                if (gattDeviceService != null)
                {
                    var characteristics = gattDeviceService.GetCharacteristics(gattCharacteristicUuids).First();

                    //If the characteristic supports Notify then tell it to notify us.
                    try
                    {
                        if (characteristics.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify))
                        {
                            characteristics.ValueChanged += characteristics_ValueChanged;
                            await characteristics.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
                        }
                    }
                    catch { }

                    //Read
                    if (characteristics.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Read))
                    {
                        var result = await characteristics.ReadValueAsync(BluetoothCacheMode.Uncached);

                        if (result.Status == GattCommunicationStatus.Success)
                        {
                            byte[] forceData = new byte[result.Value.Length];
                            DataReader.FromBuffer(result.Value).ReadBytes(forceData);
                            return forceData;
                        }
                        else
                        {
                            await new MessageDialog(result.Status.ToString()).ShowAsync();
                        }
                    }
                }
                else 
                {
                    await new MessageDialog("Access to the device has been denied =(").ShowAsync();
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
            return null;
        }

 

You can simply call the method like this:

BatteryLevel = Convert.ToInt32((await GetValue(GattCharacteristicUuids.BatteryLevel))[0]);

 

You also need a callback method that can handle the notifications.

  void characteristics_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
        {
            byte[] data = new byte[args.CharacteristicValue.Length];
            Windows.Storage.Streams.DataReader.FromBuffer(args.CharacteristicValue).ReadBytes(data);

           //Update properties
            if (sender.Uuid == GattCharacteristicUuids.BatteryLevel)
            {
                BatteryLevel = Convert.ToInt32(data[0]);
            }
        }

 

Now your app can retrieve battery level from a Bluetooth LE device. How awesome is that?

BatteryDemo.zip (289.18 kb)

Controlling an iKettle with Windows phone

A week ago I found a kettle that can be controlled over Wi-fi.
It is called iKettle and can be found over here.

When I find a device I look for two things:
Is there an app for Windows (Phone or 8)?
Can I make one?

If the answer is yes to at least one of those questions (well actually none is ok too) I know I need to buy one.

Mark Cox had already done most of the heavy lifting so I only had to implement the protocol found on this blog (Thanks Mark).
I’m a bit sad that it didn’t use http protocol, it could have replied with status 418 Ler

There are still features missing, some because I haven’t gotten around to it yet and some because there are hardware or software limitations, like you won’t be able to set up the iKettle from a Windows phone since you can’t connect directly to it.

Short app demo


 

Download the app MyKettle


Hope you enjoy the app and if you have any suggestions or comments please let med know.
Still a lot of stuff coming up =D

Windows phone 8.1 and Bluetooth LE – Getting started

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)

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)

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)

 

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

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.


Using Visual Studio 2013 as an external editor with Unity 3D

Unity is really hot right now.
Out of the box unity comes with MonoDevelop, even though I like MonoDevelop I like CodeRush even more, and I have noticed that MonoDevelop doesn't always do the things that I want.
The solution is of course to use Visual Studio instead.

1. Start unity and choose Edit –> Preferences…
2. Select External tools

In the External Script Editor drop down you may notice that Visual Studio 2013 is not part of the items.
(earlier versions will be available if you have them installed).

image


3. Choose browse… and browse to “C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe”
Now “Microsoft Visual Studio 2013” will appear in the drop down and you are all set, from now on Visual Studio will launch when you edit script files.

 

image

Using RC API on Windows 8.1

This is a short blog post on how to get RC API working on your Windows 8.1 Device.

Setup

Download RCAPI from Nuget

image_thumb[1]

 

Bluetooth

To be able to communicate thru Bluetooth you need to edit Package.appxmanifest

Add the following lines:

<Capabilities>
    ....
    <m2:DeviceCapability Name="bluetooth.rfcomm">
      <m2:Device Id="any">
        <m2:Function Type="name:serialPort" />
      </m2:Device>
    </m2:DeviceCapability>
  </Capabilities>

 

 

Pair with the device

Go into settings (win + c, Settings) , Change PC Settings, PC and Devices, Bluetooth

  image

 

The Car

Instantiate the car and you are good to go, the car class connects to the correct Bluetooth device automagically.

Ferrari458Italia ferrari = new Ferrari458Italia();

To start sending commands to the car you need to call the ConnectAsync method and call the Start method.

await ferrari.ConnectAsync();
ferrari.Start();

 

Controlling steering and speed

There are two properties controlling speed and steering.

Steering is –1 to 1 (left to right) and speed –1 to 1 (backward to forward).

In the sample projects I have used the Virtual Joystick project available on Codeplex for speed and steering, there is a modified version in the Windows Store sample project.

 

Controlling the lights

The lights are exposed through properties, to turn the light on use:

ferrari.HeadLightOn = true;

The lights available on the Ferrari 458 Italia is Headlights,blinkers (left and right) and break.

To get the lights to blink it is possible to supply an array with a light enum so if you want the blinkers to blink left

ferrari.LightSequence = new byte[] { (byte)LightEnum.LeftBlinker, 0 };

To get a more fun blinking sequence you might want to try something like this

ferrari.LightSequence = new byte[] { (byte)LightEnum.Head, (byte)LightEnum.RightBlinker, (byte)LightEnum.Break, (byte)LightEnum.LeftBlinker };

 

Trimmer

Trimmer property makes it possible to adjust the wheel orientation 0 to 15 and 8 is straight forward.

Using RC API on Windows Phone

This is a short blog post on how to get RC API working on your Windows Phone Device.

Setup

Download RCAPI from Nuget

image

 

Capabilities

To be able to communicate thru Bluetooth you need to enable ID_CAP_Proximity.

Open WMAppManifest.xml and make sure ID_CAP_Proximity is ticked.

  image

 

Pair with the device

Open Settings, Bluetooth and pair the phone with your device.

 

The Car

Instantiate the car and you are good to go, the car class connects to the correct Bluetooth device automagically.

Ferrari458Italia ferrari = new Ferrari458Italia();

To start sending commands to the car you need to call the ConnectAsync method and call the Start method.

await ferrari.ConnectAsync();
ferrari.Start();

 

Controlling steering and speed

There are two properties controlling speed and steering.

Steering is –1 to 1 (left to right) and speed –1 to 1 (backward to forward).

In the sample projects I have used the Virtual Joystick project available on Codeplex for speed and steering.

 

Controlling the lights

The lights are exposed through properties, to turn the light on use:

ferrari.HeadLightOn = true;

The lights available on the Ferrari 458 Italia is Headlights,blinkers (left and right) and break.

To get the lights to blink it is possible to supply an array with a light enum so if you want the blinkers to blink left

ferrari.LightSequence = new byte[] { (byte)LightEnum.LeftBlinker, 0 };

To get a more fun blinking sequence you might want to try something like this

ferrari.LightSequence = new byte[] { (byte)LightEnum.Head, (byte)LightEnum.RightBlinker, (byte)LightEnum.Break, (byte)LightEnum.LeftBlinker };

 

Trimmer

Trimmer property makes it possible to adjust the wheel orientation 0 to 15 and 8 is straight forward.