Sergiy Baydachnyy

Blog about technologies

How to cook Mobile Apps (node.js): table schemas, primary keys and existing tables

leave a comment »

In this post I am going to discuss how to start developing a Xamarin client application that should be connected to an existing database. As a backend I am going to use Azure Mobile Apps, because the service can minimize our work on server side and provides lots of useful features. But to get all benefits from the service, you need to know some tricks that it’s not easy to find in standard tutorials.

Today, I am going to discuss, how to use Mobile Apps in the case if you already have a database. Yes, Mobile App allows you to create a database from scratch using a graphical interface, but usually it’s not the case. I participated in lots of projects last year, and we always had a database in advance or designed it a few days before any client application. I know, it can hurt some client developers, but in many cases Xamarin app is not the centerpiece of your project. 

Before to create any database, I want to note couple things. 

First, you can develop your code for Mobile Apps in JavaScript or in C#. I like C# and don’t like JavaScript, but in the case of JavaScript/node.js implementation, you should do/know almost nothing to implement your backend. In the case of C#, you will need to generate lots of code, know Entity Framework details, and Azure Portal will provide limited number of features. In fact, C# and node.js implementations are fully different and if I don’t need to create a complex enterprise application I will always select node.js. If you want to use C# rather than JavaScript, this post will not be useful for you at all.

Second, Microsoft still supports an old implementation of the mobile backend called Azure Mobile Service. It’s not available in the new Azure portal, but there are still lots of content about it. I found that some developers continue to use Mobile Service term and it generates some messy. Try to use Mobile App everywhere. It’s the latest implementation under Azure App Service umbrella.

Ok. Let’s try to create a new database using SQL Azure. In order to have some tables and data, I would recommend selecting AdventureWorkLT database. It’s possible to do from the Azure portal. So, you can simple select New->Databases->SQL Database, and  you will be able to select the database from the “select source” field in the wizard:

image

Once you create your database, add a firewall rule to connect it from your SQL Management Studio or Visual Studio, you can note two things there:

  1. There are several schemas rather than just dbo one. It’s very important, because dbo is the default schema in Mobile Apps, and if we want to get some data from SalesLT.Product table, we have to deal with SalesLT schema;

image

  1. You can note that all tables contain primary keys of the int data type. In the case of the Product table we have ProductID as the key. It’s a very important note because some people likes to tell that you have to use guid as a data type for keys. I don’t think so, but we even should not discuss this question since we ALREADY HAVE a database that was designed by Microsoft as an example. I just want to connect my Xamarin app to it.

image

That’s all with the database and now we can create an instance of Mobile App:

image

It’s a trivial task and you should not select any specific parameters on this step.

Once you have your database and an instance of Mobile App, you can connect it together. To do it, you need to open Data Connections tab from the Mobile App dashboard and add a new connection:

image

Azure portal is clever enough to list your database. So, you should not provide any connection strings manually. You can see that a default name for the connection string is MS_TableConnectionString. DON’T TOUCH IT! Exactly this name is hardcoded in many places. 

In fact, using Add data connection tab, you are creating a new connection string that is available from the Application Settings tab. Therefore, Data Connections tab is just an easier way to create MS_TableConnectionString parameter, but you can use Application Settings as well and we are going to use this tab for some additional parameters:

image

Now, it’s time to select a programming language. In the case of C#, you can close the portal and just create all code in Visual Studio, but in our case, we want to use the portal and node.js. So, we have to initialize our empty hosting space with the right environment. It’s possible to do if you select Easy Tables tab:

image

Just click Initialize App and all needed components will be installed to your hosting space. Now, Easy Tables tab allows you to create new tables in the existing database and you can note that it doesn’t display our existing tables. Let’s try to understand, how to show our SalesLT.Product table in the list. To do it, I will just create a new table and check what is happening with my hosting space:

image

To create a new table, you can provide a table name and some security parameters for different operations with the table. 

Now, you can use Mobile App dashboard to open App Service Editor to review all available code in your hosting space:

image

You can see that for our faketable we have two files faketable.js and faketable.json. The first file imports azure-mobile-apps module and creates a table object, and the second one contains some parameters for the table:


{ 
  "softDelete" : true, 
  "autoIncrement": false, 
  "insert": { 
    "access": "anonymous" 
  }, 
  "update": { 
    "access": "authenticated" 
  }, 
  "delete": { 
    "access": "anonymous" 
  }, 
  "read": { 
    "access": "anonymous" 
  }, 
  "undelete": { 
    "access": "anonymous" 
  }}

Both files contain important information for our research. Now, we can see that there is a module that contains implementation for the backend, and if we check the module, we can find it on github: https://github.com/Azure/azure-mobile-apps-node. So, node.js implementation for Azure Mobile Apps IS IN OPEN-SOURCE. It’s great because we can find some answers there. The second file allows us to tune the backend behavior a little bit providing some parameters per table. 

In fact, in order to connect a table to our service from our database, we need to create these two files. Let’s make the experiment and create product.json and product.js files with the same content as faketable.js and faketable.json. Of course, if you go back to Easy Table, you will not be able to see any Product table due to some problems. In order to understand all these problems let’s look at faketable structure:

image

You can see that the backend created five columns for the table and the table was created in the dbo schema. So, to make our table available we have to manage several things:

  • Table schema

  • Additional columns

  • Primary key that is GUID rather than int

In the case of columns createdAt, updatedAt, version and deleted you should nor care too much. Once we fix all other problems, the framework will add all columns automatically and we will not loose our existing data. Of course, if you suddenly have some columns with the same names, you are in trouble, but it’s a very rare case.

Let’s fix the table schema. In our case we have SalesLT rather than dbo. To understand how to change the table schema for all tables, I would recommend to open node.js implementation on github: https://github.com/Azure/azure-mobile-apps-node. You can open environment.js in src/configuration/from subfolder and check all available parameters there. One of the parameters is MS_TableSchema that you can provide from the Application Settings tab on Azure portal. 

* @param {string} MS_TableSchema Default schema name for sql tables. Can override in table config

image

Therefore, we can specify SalesLT schema for the project. 

Now, you should be able to see Product table in the list, but it will not work due to the problem with the key. By default the key is GUID, but in our case it’s int and we are not going to change it because it will lead to huge amount of problems. In fact, Mobile Apps allow us to use int, but we need to configure it. In order to understand where to make all needed changes, I would recommend to check /src/data/mssql/statements/createTable.js on github. There is some code:

pkType = tableConfig.autoIncrement ? 'INT' :
 

It’s just the beginning of the line, but you can see that this line is setting up the primary key type. It’s clear that it will be int if autoIncrement property from Product.json is true.

Therefore, we fixed almost all problems, but we still have one left: the primary key MUST have “id” name. If you open src/data/mssql/statements/insert.js on github, you can find something like this:

sql += util.format('SELECT * FROM %s WHERE [id] = SCOPE_IDENTITY()', tableName);
 

You can see that id is hardcoded inside the query. I really don’t know why it was implemented in this way, but it’s something that you cannot modify it in any config file. Of course, it’s possible to assign own commands, but I am not sure if you want to implement own data provider. Additionally, it’s possible to modify existing code and redeploy it, but it’s not easy as well. The fastest way to fix the problem, it’s renaming our ProductId to id:

EXEC sp_rename 'SalesLT.Product.ProductID', 'id', 'COLUMN';  
 

It’s not the best way, because you have to check all your stored procedures, modules and other client applications. So, it will not work in enterprise. 

Now you can use Easy Tables to see all data, and all additional columns will be created.

That’s all for today and next time we will discuss how to develop a basic Xamarin application, but there are still some things to research, which you can do yourselves: find a way to work with app.js in order to use more parameters (including schema); try to understand if it’s possible to modify table schema per table (schema parameter in table config file); how to modify the code to use any primary key name.

Written by Sergiy Baydachnyy

08/22/2017 at 9:08 AM

Posted in Microsoft Azure, Xamarin

Tagged with

Playing casino with government or my message to Justin Trudeau

leave a comment »

Hi Justin,

My name is Sergii Baidachnyi, and I live in Canada for almost three years. I was relocated inside my company from Ukraine, and I am trying to be Canadian since that time. I always follow all Canadian rules and regulations, and pay taxes from my world-wide income even if I am getting my income not in Canada. In fact, I like Canada, and I thought of Canada as of my new home.

I didn’t vote for you, because I don’t have this privilege yet, but I voted for you in my heart, since you promised transparent government, clear processes and equal opportunities for everyone despite their status. Therefore, I was waiting for Canada Day as a special day to celebrate 150 years of diversity, innovation and community, and I could not imagine that I would be forced to celebrate it in the USA due to such a strange and complex discrimination that didn’t allow to get a short-term visa for my minor daughter who wanted to spend her summer vacation with me in Canada.

My 13-years old daughter, Mariia, legally lives in the USA with her mother, who is getting PhD in Purdue University. She worked hard this year, so we thought that spending her summer in Vancouver would be a good idea. We would visit lakes for fishing, u-pick raspberry on local farms, hiking, cycling, take private ballet lessons in Vancouver ballet and so on. In February, we requested a new foreign passport from Ukraine to avoid any problems with expiration dates, updated her I-20 form and, finally, at the end of May we filled our application for a visitor visa. Of course, we submitted all requested documents and I had explained that my daughter could have been a part of my PR application or could have had a student permit by law when I moved to Canada in 2014, but I didn’t ask for anything like this because she is going to spend a couple more years in the USA.

Everything looked good and system confirmed a few times that once any additional documents are required, they would be requested:

clip_image002

And here:

clip_image004

The processing time to receive Canadian visa from the USA is 21 days, but it was manageable.

You may be surprised, but there is no way to call to New York office (where her documents were processed), there is just a web form, and even the call center cannot answer anything about visa processes there (after 40 minutes waiting on the line). So after 21 days have passed, and I did not get any reply about her documents, I contacted Canadian visa center through the web form, explaining that my daughter has to go back to school in the beginning of August and we would be happy to get the visa before this time. The answer that I got from the government was useless:

clip_image006

It looks like an automatic reply about nothing. Pay attention that at the same time I emailed to the USA consulate in Vancouver about extending her F-2 visa to the US (after all, we found that we don’t need it to go back to the USA), and you can compare how many details the answer of the American officials has compared to the answer from the Canadian government (including many ways to contact them):

clip_image008

Finally, in 30 days after application was submitted we got a standard message that our visa application is refused:

clip_image010

Of course, my first question was: Is it a casino? You have to put some money into the system, click a button and see if you win. I answered all questions, provided all the requested documents, and the system has been telling me all the time that everything was OK, and should some additional documents be needed they would be requested. But the visa was refused without attempts to request these documents, any replies to my inquiries, and after more than 4 weeks of processing time!

I cannot explain it at all. Should I assume that a person in the New York office is discriminating people by status or nationality? If it’s true, I would like to know if it’s an official government position? Probably, they need to reach some internal KPIs (like number of refused applications) or the process is simply broken. In this case we cannot talk about clear processes at all. It’s even not about why Donald Trump’s administration thinks that my daughter may attend the US school, but the Canadian government has an opposite opinion about her legal presence in the USA (not even Canada). It’s exactly about the absence of the clear processes and transparent government, because there is no way to make government employees be responsible for their discriminating decisions.

You can invest huge amount of money to IT infrastructure, but it’s really not helpful, because a person in the New York office will waste all this investment being is too lazy to find an attached I-20 form (which was attached to the application in our case) or request any additional documents that system hadn’t ask before – it’s much easier to click ‘refuse’ and request one more application (and make people wait another 30 days plus collect additional processing fee).

You know, last year I participated in some projects to make Canadians’ lives better and safer. We developed a software solution to help people manage after global disasters, we worked on a solution for a better environment for people with disabilities, etc. So, if you need my help to develop a bot that will be able to improve the process, just let me know.

In two hours after our visa was refused I opened the Twitter and found this message:

clip_image012

I really wanted to recommend Canada as a host for all International events, but I have mixed feelings now. I don’t want people to go through the same nightmare with irresponsible government officials that I did. I still hope that my issue is not related to Canada in general, and it’s just New York office’s mistake. But my daughter’s vacation is ruined anyway.

Of course, I resubmitted the application, paid the fee again, attached a huge amount of additional documents to my case, but Mariia will not need any visas in 30 days because she will start her classes at the US school. I filled out one more web form asking them to speed-up the process, but there is no much faith any person reads those or cares. This time I didn’t even receive an auto reply. That’s why I am in the USA right now and I am spending my Canadian money here to grow their economy.

Best regards,

Sergii

Written by Sergiy Baydachnyy

07/07/2017 at 5:08 PM

Posted in Uncategorized

UWP: Working with Bluetooth (part 5: Bluetooth RFCOMM)

leave a comment »

Windows 10 API supports not just Bluetooth Low Energy devices, but allows you to utilize RFCOMM protocol as the most widespread since Bluetooth invention. Even if your module doesn’t support BLE, you always can use RFCOMM. As in the case of BLE Windows 10 allows you to publish RFCOMM services or work with other services as a client.

I decided to implement client only, and for a server I used a cheap Bluetooth module HC-06. It’s possible to buy the module for couple dollars and you can find lots of videos and examples about how to connect it to Arduino board. But you can use any available Bluetooth module. Just in case you can find a schema below:

clip_image002

My module wasn’t on a plate with a voltage regulator. So, I decided to add a voltage divider for TX->RX connection, because Arduino generate 5 volts there rather than 3.3 volts. If you have a module like on the schema above (with the regulator), you still can use the divider, and it will not break your circuit.

To communicate with the module from Arduino, you can simply use the serial port. So, I connected TX and RX pins on Arduino to RX and TX pins on the module. Additionally, I connected 3.3V and GRN on Arduino to VCC and GRN on the module.

I setup my module to use 115200 speed and changed the name of the module to rfcommhc06. You can do it connection the module to your computer using USB to Serial adapter and execute some AT commands (AT+NAMErfcommhc06 and AT+BAUD8).

Finally, I could implement a very simple code for Arduino:

void setup()
{
   Serial.begin(115200);
   pinMode(13,OUTPUT);
}
byte blue;
void loop()
{
   if(Serial.available())
   {
      blue=Serial.read();
      Serial.write(blue);
      if (blue==3)
      {
         digitalWrite(13,HIGH);
      }
      else if(blue==2)
      {
         digitalWrite(13,LOW);
      }
      Serial.write(blue);
   }
}

This code read data from serial port using infinity loop and one there is 3, it sends high voltage to pin number 13. In the case if 2 is in the stream, it sends low voltage to pin 13. Because pin 13 are connected with a LED on Arduino Uno boards, the led will switch status between on and off depends on input data. At the end of each iteration, I send all incoming data back.

If you finish your circuit and deploy the code successfully, it’s time to start developing a client for Windows 10.

The first part of our code will look similar to BLE example. We have to start watcher and declare handlers for Added and Removed events:

DeviceWatcher deviceWatcher;
DataWriter tx;
DataReader rx;
StreamSocket stream;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
   deviceWatcher = DeviceInformation.CreateWatcher(
      "System.ItemNameDisplay:~~\"rfcommhc\"",
      null,
      DeviceInformationKind.AssociationEndpoint);
   deviceWatcher.Added += DeviceWatcher_Added;
   deviceWatcher.Removed += DeviceWatcher_Removed;
   deviceWatcher.Start();
   base.OnNavigatedTo(e);
}

The DeviceWatcher_Added method will looks different compare to BLE example.

private async void DeviceWatcher_Added(DeviceWatcher sender,
   DeviceInformation args)
{
   var device = await BluetoothDevice.FromIdAsync(args.Id);
   var services = await device.GetRfcommServicesAsync();
   if (services.Services.Count>0)
   {
      var service = services.Services[0];
      stream = new StreamSocket();
      await stream.ConnectAsync(service.ConnectionHostName,
      service.ConnectionServiceName);
      rx = new DataReader(stream.InputStream);
      tx = new DataWriter(stream.OutputStream);
      await this.Dispatcher.RunAsync(
         Windows.UI.Core.CoreDispatcherPriority.Normal,
         () => { switchLed.IsEnabled = true; });
      deviceWatcher.Stop();
   }
}

First, we use the BluetoothDevice class rather than BluetoothLEDevice. Once we have a reference to the device, the GetRfcommServiceAsync method helps us to get list of all available services. Our Arduino code is very primitive and we have just one service. Once we have a reference to the service, we can use the StreamSocket class to establish a connection to the Bluetooth module and get references to input and output streams.

Finally, we can use DataReader and DataWriter classes to start working with the module like with a virtual serial port:

private async void ToggleSwitch_Toggled(object sender, RoutedEventArgs e)
{
   byte data = 2;
   if (switchLed.IsOn)
   {
      data = 3;
   }
   tx.WriteByte(data);
   await tx.StoreAsync();
   uint buf;
   buf = await rx.LoadAsync(1);
   var symbol = rx.ReadByte();
   Debug.WriteLine(data);
}

If you want to develop something more for Arduino and Windows 10, I would recommend to use Remote Wiring project (https://github.com/ms-iot/remote-wiring) that can help you control Arduino board using your own UWP application.

Written by Sergiy Baydachnyy

05/19/2017 at 10:58 PM

UWP: Working with Bluetooth (part 4: Publishing GATT services)

leave a comment »

Thanks to new Bluetooth Low Energy API in Creators Update, UWP applications can publish GATT services playing a virtual peripheral role. It makes sense if you develop a hardware hub on Windows 10 that should be connected to different peripheral devices (not just Bluetooth, but ZigBee, Z-WAVE and even by wires) and want to use Bluetooth as a communication protocol between your phones, computers and the hub. In this case, the hub can read data from the peripheral devices and route these data as a set of Bluetooth services.

Of course, to publish anything as a BLE service you have to make sure that a radio module on your computer supports peripheral role. I didn’t find any list or recommendations yet, but it’s really not easy to find a device for tests. Even if a radio module based on a chip that can work as a transmitter, it means nothing. All my five computers including Surface Book don’t support peripheral role, but I could find at least one device: Raspberry Pi 3 that has embedded Bluetooth module. It’s strange, but using Raspberry Pi 3 you will not be able to implement beacons, but it works fine as a virtual peripheral device. If you have Raspberry Pi 2, it will not work, because both recommended external modules don’t support peripheral role.

To check if your computer supports the peripheral role, you can use the BluetoothAdapter class and check the IsPeripheralRoleSupported property. If it’s true, your device can work as a Bluetooth peripheral device.

Let’s discuss how to publish own services if your module supports the peripheral role. I will create a service that is similar to STEVAL-IDB007V1 default service that we discussed in the beginning. So, I am going to create two services. The first one will publish acceleration data and the second one will publish temperature and pressure. First of all we need to create an instance of the GattServiceProvider class. It’s possible to do using the CreateAsync static method of the class:

var serviceResult =
    await GattServiceProvider.CreateAsync(Guid.Parse(SensorUUIDs.UUID_ACC_SERV));
accService = serviceResult.ServiceProvider;
accService.AdvertisementStatusChanged += AccService_AdvertisementStatusChanged;

You can see that to use the CreateAsync method it’s enough to pass a GUID as a parameter. Pay attention that Bluetooth specification contains some reserved GUIDs for adopted services. So, if you create something from scratch, it’s better to check all reserved GUIDs. In the code above I declared an event handler for the AdvertisementStatusChanged event in order to make sure that my service is started.

Once our service is created, we can add characteristics to it. The following code shows how to do it:

var param = new GattLocalCharacteristicParameters();
param.CharacteristicProperties =
    GattCharacteristicProperties.Indicate |
    GattCharacteristicProperties.Read;
param.WriteProtectionLevel = GattProtectionLevel.Plain;
param.UserDescription = "accelerometer";
var charResult=
    await accService.Service.CreateCharacteristicAsync(
        Guid.Parse(SensorUUIDs.UUID_ACC_DATA),param);
accData = charResult.Characteristic;
accData.ReadRequested += AccData_ReadRequested;

To create a characteristic, you can use CreateCharacteristicAsync method, but prior to call it we need to prepare parameters for the characteristic. You can see that our characteristic is indicatable and supports Read operation. You can add Notify to support notification mechanism. Because our characteristic supports Read, we need to handle ReadRequested event to provide all needed data. Below you can see implementation for the handler:

private async void AccData_ReadRequested(GattLocalCharacteristic sender,
    GattReadRequestedEventArgs args)
{
    var deferral=args.GetDeferral();
    var request = await args.GetRequestAsync();
    var writer = new DataWriter();
    writer.WriteBytes(new byte[6] { 0x12, 0x12, 0x12, 0x12, 0x12, 0x12 });
    request.RespondWithValue(writer.DetachBuffer());
    deferral.Complete();
}

In this code if you forget to use deferral, the code will generate a runtime exception. In the beginning if the chapter my STEVAL-IDB007V1 board had some sensors, but Raspberry Pi 3 doesn’t contain accelerometer or temperature sensors. So, I generate fake values just to test if it works at all, but if you want, you can connect real sensors to your Raspberry Pi 3.

Finally, we are ready to advertise the service.

accService.StartAdvertising(
    new GattServiceProviderAdvertisingParameters() {
        IsDiscoverable = true, IsConnectable = true });

Using StartAdvertising method we need to initialize IsDiscoverable and IsConnectable to true.

Opening my code on github you can find implementation for the second service with similar implementation. To test this service, we can use our first application in this chapter or any BLE scanner.

Written by Sergiy Baydachnyy

05/18/2017 at 3:11 AM

UWP: Working with Bluetooth (part 3: Advertisement)

leave a comment »

Bluetooth Low Energy can be used to implement beacons. Usually beacons are not designed for pairing and simply broadcast data making them available for everybody. You can use beacons in a mall to notify shoppers about some deals, or in quests, notifying players about some treasures in the area, or even for people with disabilities notifying them about surrounding environment. Today, almost all mobile devices support Bluetooth Low Energy and advertisement feature there and you even can find some SDKs for Android and iOS that implement own data payload specifications (Eddystone and iBeacon) based on Bluetooth Low Energy Advertisement. Thanks to the specifications you can understand what kind of data is broadcasting and use them in your applications even if a beacon was implemented by somebody else.

In the case of Universal Windows Platform you have access to a special namespace Windows.Devices.Bluetooth.Advertisement that can help you receive and send data using BLE Advertisement. Using this namespace you can implement classes that will use existing payload specifications or simply broadcast data in your own way.

To implement advertisement example, I am not going to use any microcontroller. Instead, I would recommend to use just Windows 10 computers. In general, any Windows 10 computer can send and receive advertisement, but in some cases, it’s not true and some Bluetooth radio adapters don’t support broadcasting advertisement data.

To understand if your adapter supports broadcasting, you can simply execute the following line of code:

BluetoothAdapter adapter = await BluetoothAdapter.GetDefaultAsync();

And just check adapter’s property using Debugger:

clip_image002

You can see that there is a property IsAdvertisementOffloadSupported that shows if your adapter can broadcast advertisement. In my case this property is true.

Ok, let’s start with code that broadcast some data:

BluetoothLEAdvertisementPublisher publisher;
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    var manufacturerData =
        new BluetoothLEManufacturerData();
    var writer = new DataWriter();
    writer.WriteString("Buy our socks for a dollar");
    manufacturerData.CompanyId = 0xFFFE;
    manufacturerData.Data = writer.DetachBuffer();
    publisher =
        new BluetoothLEAdvertisementPublisher();
    publisher.Advertisement.ManufacturerData.Add(manufacturerData);
    publisher.StatusChanged += Publisher_StatusChanged;
    publisher.Start();
    base.OnNavigatedTo(e);
    }
private void Publisher_StatusChanged(BluetoothLEAdvertisementPublisher sender,
    BluetoothLEAdvertisementPublisherStatusChangedEventArgs args)
{
    Debug.WriteLine(args.Status.ToString());
}

In our case we made all preparation work using the BluetoothLEManufacturerData class. We used this class just in order to simplify our work, because we are not going to broadcast anything special, but in the most cases you will use the DataSections property rather than the ManufacturerData property. Exactly DataSections contains all payloads and filling ManufacturerData you automatically add a section to DataSections collection. But working with the BluetoothLEAdvertisementDataSection class to fill DataSections is a little bit more complicated, because you need to know different data types from BLE specification, form a header that will include special flags and size of the buffer and so on. In the case of the BluetoothLEManufacturerData class you can write your data directly and all what you need is just provide a company id. Using this link (https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers), you can find some hardcoded company ids for companies like Apple and Microsoft. Therefore, I selected the first available ID from the end. Additionally, I implemented the StatusChanged event handler to make sure that my application starts broadcasting data.

Therefore, we have a publisher that broadcasts a text message. Now, we can create a watcher that will receive our advertisement. Let’s look at the following code:

private BluetoothLEAdvertisementWatcher watcher;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    watcher = new BluetoothLEAdvertisementWatcher();
    watcher.SignalStrengthFilter.InRangeThresholdInDBm = -70;
    var manufacturerData =
        new BluetoothLEManufacturerData();
    manufacturerData.CompanyId = 0xFFFE;
    watcher.AdvertisementFilter.Advertisement.ManufacturerData.Add(
        manufacturerData);
    watcher.Stopped += Watcher_Stopped;
    watcher.Received += Watcher_Received;
    watcher.Start();
    base.OnNavigatedTo(e);
}
private void Watcher_Stopped(BluetoothLEAdvertisementWatcher sender,
    BluetoothLEAdvertisementWatcherStoppedEventArgs args)
{ }
private void Watcher_Received(BluetoothLEAdvertisementWatcher sender,
    BluetoothLEAdvertisementReceivedEventArgs args)
{
    Debug.WriteLine(args.Advertisement.LocalName);
    Debug.Write(args.RawSignalStrengthInDBm);
    if ((args.Advertisement.ManufacturerData.Count>0))
    {
        DataReader data =
            DataReader.FromBuffer(args.Advertisement.ManufacturerData[0].Data);
        Debug.Write(data.ReadString(
            args.Advertisement.ManufacturerData[0].Data.Length));
    }
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    watcher.Stop();
    base.OnNavigatedFrom(e);
}

In fact, it’s not a complex task to create a watcher, but implementing your own application, you should not always watch all advertisements around. It’s better to watch exactly beacons that were designed for your application. That’s why the BluetoothLEAdvertisementWatcher class allows us to setup filters. In our case we have two filters: signal strength and company id. It can help us understand that we are too close to the beacon and that it’s exactly our service.

Working with beacons we have to note several things:

  • In most cases you will work with the DataSections property. So, if you want to develop something cool, you have to learn Bluetooth LE Advertisement specification. Additionally, you may need to implement Eddystone and iBeacon specifications;
  • You can see that beacon broadcasts the same data all time and if you run our application in the Debug mode, you will be able to see that the application prints advertisement message all time. So, it’s important to check if you already received the message to avoid duplicate actions;
  • Above we implemented just foreground applications, but it’s not wisely. Probably, our application will not stay open all time even in the case of watcher. In the case of publisher, there is no sense to implement interface at all. That’s why it’s important to know how to work with Bluetooth in background. We will discuss background approach later;

Written by Sergiy Baydachnyy

05/08/2017 at 10:27 PM

UWP: Working with Bluetooth devices (part 2: pairing)

leave a comment »

Implementing the previous example, I didn’t pair my device with my Windows 10 PC, but in the most cases you cannot omit pairing. Exactly thanks to pairing you can establish trust communications with a Bluetooth device that will allow your application get access to characteristics, lock the device to your computer and many other things. Windows 10 allows you to pair any device (not just Bluetooth) using Settings window:

clip_image002

But you can pair your devices directly from your application. In order to do it you can use the same DeviceInformation class that we used to track available devices.

Let’s modify our code. We will check the status and if the device is not paired we will pair it. You can use the following code in order to pair the device and navigate the application to the next page:

private async void deviceListView_ItemClick(object sender, ItemClickEventArgs e)
{
    var item = e.ClickedItem as DeviceInformation;
    if (item.Pairing.CanPair)
    {
        var result = await item.Pairing.PairAsync();
        if ((result.Status == DevicePairingResultStatus.Paired) ||
            (result.Status == DevicePairingResultStatus.AlreadyPaired))
        {
            this.Frame.Navigate(typeof(DevicePage), item);
        }
    }
    else if (item.Pairing.IsPaired == true)
    {
        this.Frame.Navigate(typeof(DevicePage), item);
    }
}

You can see that we used Pairing property to get a reference to an object of DeviceInformationPairing type. Using it we can check if the device is already paired, and pair the device if needed.

Pay attention that Windows is caching all paired devices. So, once your device is paired, you will be able to see it in the list, even if the device is not present physically. It’s a problem and it’s better to check if the device is still available.

Of course, pairing process may require some actions from user side. For example, STEVAL-IDB007V1 evaluation board requires to inter a pin (123456 by default) to complete the pairing process. So, the PairAsync method will show all needed dialogs:

clip_image004

Once the device is paired, the application will display the next page with data. If you navigate your application back, you will be able to see that the device is already paired:

clip_image006

UWP API supports one more way for pairing: custom pairing mechanism. Using this way, you can create your own dialogs that will requires all needed pins or any additional information. In our case we can suppress the default pin dialog and hardcode the default pin in code. The following code demonstrates this feature:

private async void deviceListView_ItemClick(object sender, ItemClickEventArgs e)
{
    var item = e.ClickedItem as DeviceInformation;
    if (item.Pairing.CanPair)
    {
        //var result = await item.Pairing.PairAsync();
        var customPairing = item.Pairing.Custom;
        customPairing.PairingRequested += CustomPairing_PairingRequested;
        var result =
            await customPairing.PairAsync(DevicePairingKinds.ProvidePin);
        customPairing.PairingRequested -= CustomPairing_PairingRequested;
        if ((result.Status == DevicePairingResultStatus.Paired) ||
            (result.Status == DevicePairingResultStatus.AlreadyPaired))
        {
            this.Frame.Navigate(typeof(DevicePage), item);
        }
    }
    else if (item.Pairing.IsPaired == true)
    {
        this.Frame.Navigate(typeof(DevicePage), item);
    }
}
private void CustomPairing_PairingRequested(
    DeviceInformationCustomPairing sender, DevicePairingRequestedEventArgs args)
{
    args.Accept("123456");
}

You can see that we used Custom property in order to invoke custom pairing process. Using this property and PairAsync method there we can activate pairing process. It will generate a special event PairingRequested where we can provide all needed information. In our case we simply use Accept method with the pin as a parameter.

Of course, Microsoft try to avoid any security issues with pairing. So, even in the case of custom pairing users will be able to see a notification window:

clip_image008

One more benefit due to pairing is ability to use a watcher to list services. In the previous example we used a snapshot of all services, but in the real life this process may take some time or some services may be available later. Using a watcher, you can control the process showing progress and all recognized services dynamically. Below you can find modified code that uses DeviceWatcher class to list all services for a selected device:

public async void StartReceivingData()
{
    leDevice = await BluetoothLEDevice.FromIdAsync(device.Id);
    string selector = "(System.DeviceInterface.Bluetooth.DeviceAddress:=\"" +
        leDevice.BluetoothAddress.ToString("X") + "\")";
    watcher = DeviceInformation.CreateWatcher(selector);
    watcher.Added += Watcher_Added;
    watcher.Removed += Watcher_Removed;
    watcher.Start();
    timer.Interval = new TimeSpan(0, 0, 1);
    timer.Tick += Timer_Tick;
    timer.Start();
}
private async void Watcher_Removed(DeviceWatcher sender,
    DeviceInformationUpdate args)
{ }
private async void Watcher_Added(DeviceWatcher sender, DeviceInformation args)
{
    var service = await GattDeviceService.FromIdAsync(args.Id);
    if (service!=null)
    {
        switch (service.Uuid.ToString())
        {
        case SensorUUIDs.UUID_ENV_SERV:
            InitializeTemperatureSensor(service);
            InitializePressureSensor(service);
        break;
        case SensorUUIDs.UUID_ACC_SERV:
            InitializeAccelerationSensor(service);
        break;
        }
    }
}

You can see that code is not very complex, but you can extend your UI now showing progress.

Written by Sergiy Baydachnyy

04/28/2017 at 11:08 PM

UWP: Working with Bluetooth devices (part 1)

leave a comment »

Code: Chapter26_BluetoothData on https://github.com/sbaidachni/Win10BookSamples

Universal Windows Platform supports really great Bluetooth API that allows us to build applications that are connected to various kinds of wiring devices. Your application can support Bluetooth LE (Low Energy, 4.x version) or even previous versions of the protocol, and I am going to cover how to use all of them, but let’s start with Bluetooth LE.

Bluetooth Low Energy

In order to build couple samples, I would recommend to use any BLE development board. The board should contain several sensors and a preinstalled example. In my case I have an evaluation board from STMicroelectronics (STEVAL-IDB007V1) based on BlueNRG-1 Bluetooth chip. This board contains a 3D digital accelerometer, a gyroscope (preinstalled example doesn’t return data from gyroscope by design) and a pressure sensor with an embedded temperature sensor. All these things we will be able to use in our application.

clip_image002

In fact, you can use any BLE device like a smart bulb that you can buy in Home Depot, but prior to buy anything you need to make sure that there is a document that describes all services and characteristics. Of course, using UWP API you will be able to read all available characteristics, but in the case of “no name” devices it’s really hard to understand how to interpret incoming data.

Universal Windows Platform contains five namespaces with Bluetooth keyword including Windows.Devices.Bluetooth. Exactly this namespace contains the BluetoothLEDevice class that will help us to get information about all available services and characteristics. But prior to start creating any instance of this class we need to implement interface that will allow a user to select our device from the list. Of course, we can list all device in code and connect to any of them without any interaction with the user, but it’s always better to get confirmation from the user.

Therefore, I am going to implement UI that will use some criteria to list all available devices and allows users to select one from the list. We can do it using the Windows.Devices.Enumeration namespace. In general, the namespace doesn’t contain any Bluetooth related classes. Instead, there are several universal classes that allow us to list anything that is connected to our computer/phone. This namespace even supports DevicePicker and DevicePickerFilter classes that can simplify our work thanks to embedded dialogs. But using these classes is a trivial task:

DevicePicker picker = new DevicePicker(); picker.Filter.SupportedDeviceSelectors.Add
    BluetoothLEDevice.GetDeviceSelectorFromPairingState(false));
picker.Filter.SupportedDeviceSelectors.Add(
    BluetoothLEDevice.GetDeviceSelectorFromPairingState(true));
picker.Show(new Rect(x, y, width, height));

Code below will show the following dialog that display all paired and non-paired Bluetooth Low Energy devices:

clip_image004

The dialog support DeviceSelected event that helps us to understand which device is selected. Alternatively, you can use PickSingleDeviceAsync method to avoid any event handlers. You can see that DevicePicker can display any devices. So, in order to display just BLE devices we need to setup a filter using Advanced Query Syntax string. ADS can be a little bit complex to setup. That’s why we used the BluetoothLEDevice class to get access to some predefined strings. Using the GetDeviceSelectorFromPairingState method we can return all BLE devices that are paired or non-paired. Adding both strings to the filter, we can select all available BLE devices.

In my examples, I am not going to use embedded dialogs. Instead of using them, I decided to build my own interface. In order to implement it, I need to create a page that will display a list of all devices in my own way. Using the DeviceInformation class I can find all BLE devices using the FindAllAsync method, but this approach is not the best one, because, I have to assume that users can activate new Bluetooth devices “on fly”. So, we have to look at all changes all time rather than use a snapshot and we cannot use just the FindAllAsync method in the DeviceInformation class. Instead, we will create a watcher that will notify us about any changes in the list of available devices. In order to do that, we can use the DeviceWatcher class that is available in the Windows.Devices.Enumeration namespace. Let’s look at the following code:

DeviceWatcher deviceWatcher;
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    deviceWatcher = DeviceInformation.CreateWatcher(
        "System.ItemNameDisplay:~~\"BlueNRG\"",
        new string[] {
            "System.Devices.Aep.DeviceAddress",
            "System.Devices.Aep.IsConnected" },
        DeviceInformationKind.AssociationEndpoint);
    deviceWatcher.Added += DeviceWatcher_Added;
    deviceWatcher.Removed += DeviceWatcher_Removed;
    deviceWatcher.Start();
    base.OnNavigatedTo(e);
}

You can see that in order to create the watcher, we used the CreateWatcher static method that you can find in the DeviceInformation class. This method accepts several parameters. Using the first one we can provide a filter that can help us list just needed devices. It’s the same Advanced Query Syntax string that we used before, but in this case, we created it from scratch rather than using a predefined one. It’s a good idea to show different approaches and I used a filter that helps me find exactly devices that contain BlueNRG string in their names. To implement this filter I used the System.ItemNameDisplay property. Because all my dev kit is available as BlueNRG by default, my application will show just my device. Of course, we should not hardcode any names and it’s better to use less restrictive filter like we did in the first block of codeIf you want to find more information about possible ADS properties you can visit this page.

The second parameter is a set of properties that should be available for a device. In this case we requested DeviceAddress and IsConnected properties, but I used it just for the demo. I assume that you will not able to find many different devices with BlueNRG name around, so, you can simply remove this parameter.

Finally, we have to pass the DeviceInformationKind flag. In our case it should be AssociationEndpoint that is true for all Bluetooth LE devices that advertise their interface.

Once we create the watcher, we need to assign event handlers to Added and Removed events and start the watcher. Pay attention that if you forget to assign Removed event handler, the watcher will not work. I am not sure “why”, but once I assigned an empty event handler, the watcher started without any problem. Here is my code:

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    deviceWatcher.Stop();
    base.OnNavigatedFrom(e);
}
private void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
{
    //throw new NotImplementedException();
}
private async void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
{
    var device = await BluetoothLEDevice.FromIdAsync(args.Id);
    var services=await device.GetGattServicesAsync();
    foreach(var service in services.Services)
    {
        Debug.WriteLine($"Service: {service.Uuid}");
        var characteristics=await service.GetCharacteristicsAsync();
        foreach (var character in characteristics.Characteristics)
        {
            Debug.WriteLine($"Characteristic: {character.Uuid}");
        }
    }
}

Now, you can run the code above and it will start looking for a BlueNRG device and once it’s available, it will print all supported services and characteristics to the Output window. I got the following data for my device:

Service: 00001801-0000-1000-8000-00805f9b34fb
Characteristic: 00002a05-0000-1000-8000-00805f9b34fb
Service: 00001800-0000-1000-8000-00805f9b34fb
Characteristic: 00002a00-0000-1000-8000-00805f9b34fb
Characteristic: 00002a01-0000-1000-8000-00805f9b34fb
Characteristic: 00002a04-0000-1000-8000-00805f9b34fb
Service: 02366e80-cf3a-11e1-9ab4-0002a5d5c51b
Characteristic: e23e78a0-cf4a-11e1-8ffc-0002a5d5c51b
Characteristic: 340a1b80-cf4b-11e1-ac36-0002a5d5c51b
Service: 42821a40-e477-11e2-82d0-0002a5d5c51b
Characteristic: a32e5520-e477-11e2-a9e3-0002a5d5c51b
Characteristic: cd20c480-e48b-11e2-840b-0002a5d5c51b

You can see that the device supports four services and each of them contains from one to three characteristics. In order to understand what is it, we need to visit STMicroelectronics web-site (st.com) and find a document that describes all these things. The document called UM2071: BlueNRG-1 development kit. If you type this name in the Search box and open the Resource tab, you will be able to find it. This document contains much information, but we need just a table with characteristics (Figure 20):

clip_image006

Looking at this table we can note service UUIDs for Acceleration, Temperature and Pressure. It’s exactly that I am going to display in my application. Potentially we can check Free Fall, but I have just one board, and I will try to avoid any scary experiments.

Pay attention that Bluetooth LE standard contains some standard profiles that can help you recognize some standard services. Profiles, it’s something that operating system uses to connect any Bluetooth mouse or stream video/audio between different devices (not BLE, but the idea is the same). In some case you will need to rely on standard profiles, but in some cases, you can create your own. Looking at the table below you can see that our development board implements standard attribute and generic access profiles. Thanks to them Windows can read some information about the device like device name. But all other services implement custom profiles. It’s ok if your device is not going to support any standard feature and it can be a problem for you if you want to connect some low-cost Bluetooth devices to your application. I found that lots of devices from “no name” companies implement own custom profile and if you want to connect your phone or tablet to these devices you have to download an application. But once you want to create your own application, it’s really hard to find how the device works.

Ok. Now we know where to find information about supported services and characteristics, but we still didn’t finish our main page. So, let’s do it.

In order to store information about all available devices I will use a collection that will store references to DeviceInformation objects:

ObservableCollection<DeviceInformation> deviceList =
    new ObservableCollection<DeviceInformation>();

The collection should be observable because we are going to bind it to our interface and it should track any changes dynamically.

Now, we can modify our event handlers:

private async void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
{
    var toRemove = (from a in deviceList where a.Id == args.Id select a).FirstOrDefault();
    if (toRemove != null)
        await this.Dispatcher.RunAsync(
            Windows.UI.Core.CoreDispatcherPriority.Normal,
            () => { deviceList.Remove(toRemove); });
}
private async void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
{
    await this.Dispatcher.RunAsync(
        Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => { deviceList.Add(args); });
}

You can see that we use the handlers to track changes in the list. Pay attention that both handlers are running in non-UI thread. So, we have to invoke dispatcher to modify our collection.

Finally, we can build UI. It will be primary a ListView that will display Id, Name and Pairing properties:

<ListView Grid.Row="2" Name="deviceListView" ItemsSource="{Binding}" IsItemClickEnabled="True" ItemClick="deviceListView_ItemClick" HorizontalAlignment="Center">
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid Margin="10">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100"></ColumnDefinition> 
                    <ColumnDefinition Width="Auto"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                    <RowDefinition></RowDefinition>
                </Grid.RowDefinitions>
                <Image Source="Assets/stlogo.png" Margin="10" Grid.RowSpan="3"></Image>
                <TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding Id}"></TextBlock>
                <TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding Name}"></TextBlock>
                <StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal">
                    <TextBlock Text="Can be paired: "></TextBlock>
                    <TextBlock Text="{Binding Pairing, Converter={StaticResource pairingConv}, Mode=OneWay}"></TextBlock>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

To run this code, you need to add an empty event handler for ItemClick. We will implement it later. Additionally, you can use OnNavigatedTo to set DataContext property and activate binding:

this.DataContext = deviceList;

Running this code, we will see the following window:

clip_image008

Pay attention that our device is still not paired, but in order to start reading data from it we should not pair it. This feature is available since Windows 10 Creators Update. All previous UWP versions requires pairing prior start reading any data.

Ok. Now we can implement ItemClick event handler and once a user selects the device, we may navigate our application to the second page:

private void deviceListView_ItemClick(object sender, ItemClickEventArgs e)
{
    this.Frame.Navigate(typeof(DevicePage), e.ClickedItem);
}

In order to simplify work with all sensors I created a base class that implements all needed features to read values from characteristics:

public class SensorBase:IDisposable
{
    protected GattDeviceService deviceService;
    protected string sensorDataUuid;
    protected byte[] data;
    protected bool isNotificationSupported = false;
    private GattCharacteristic dataCharacteristic;
    public SensorBase(GattDeviceService dataService, string sensorDataUuid)
    {
        this.deviceService = dataService;
        this.sensorDataUuid = sensorDataUuid;
    }
    public virtual async Task EnableNotifications()
    {
        isNotificationSupported = true;
        dataCharacteristic = (await deviceService.GetCharacteristicsForUuidAsync(
            new Guid(sensorDataUuid))).Characteristics[0];
        dataCharacteristic.ValueChanged += dataCharacteristic_ValueChanged;
        GattCommunicationStatus status =
            await dataCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
                GattClientCharacteristicConfigurationDescriptorValue.Notify);
    }
    public virtual async Task DisableNotifications()
    {
        isNotificationSupported = false;
        dataCharacteristic = (await deviceService.GetCharacteristicsForUuidAsync(
            new Guid(sensorDataUuid))).Characteristics[0];
        dataCharacteristic.ValueChanged -= dataCharacteristic_ValueChanged;
        GattCommunicationStatus status =
            await dataCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
            GattClientCharacteristicConfigurationDescriptorValue.None);
    }
    protected async Task<byte[]> ReadValue()
    {
        if (!isNotificationSupported)
        {
            if (dataCharacteristic == null)
                dataCharacteristic = (await deviceService.GetCharacteristicsForUuidAsync(
                    new Guid(sensorDataUuid))).Characteristics[0];
            GattReadResult readResult =
                await dataCharacteristic.ReadValueAsync(BluetoothCacheMode.Uncached);
            data = new byte[readResult.Value.Length]; 
            DataReader.FromBuffer(readResult.Value).ReadBytes(data); 
        }
        return data;
    }
    private void dataCharacteristic_ValueChanged(GattCharacteristic sender,
        GattValueChangedEventArgs args)
    {
        data = new byte[args.CharacteristicValue.Length];
        DataReader.FromBuffer(args.CharacteristicValue).ReadBytes(data);
    }
    public async void Dispose()
    {
        await DisableNotifications();
    }
}

In general, the most important method in this class is ReadValue, but BLE supports notification mechanism. From the GATT table, we can see that our board supports at least one sensor that allows us use notifications to receive updated data. This is accelerometer sensor. Of course, I could read data from accelerometer using just ReadValueAsync method, but I wanted to show how to use notifications. It’s not always true that your device will send updated data several time per second and in this case notifications allows to save some time, avoiding not needed queries. You can see that in order to enable notification for a characteristic we simply have to add a special descriptor using WriteClientCharacteristicConfigurationDescriptorAsync method. Once the descriptor is assigned, we will be able to receive messages with new values for the characteristic.

Using our base class, it’s not a problem to create three more classes that describe our sensors. Here is an example for the temperature sensor:

public class TemperatureSensor: SensorBase
{
    public TemperatureSensor(GattDeviceService dataService) :
        base(dataService, SensorUUIDs.UUID_ENV_TEMP) { }
    public async Task<double> GetTemperature()
    {
        byte[] data = await ReadValue();
        return ((double)BitConverter.ToInt16(data,0))/10;
    }
}

Pay attention that by default our sensors don’t use notification mechanism. So, if you want to enable notification for accelerometer, it’s needed to call EnableNotification method.

protected async void InitializeAccelerationSensor(GattDeviceService service)
{
    accSensor = new AccelerationSensor(service);
    await accSensor.EnableNotifications();
}

Finally, we can create a view model and bind it to our interface. I am not going to discuss all aspects of the view model, but want to concentrate your attention around couple methods. The first one is a method that initializes everything:

public async void StartReceivingData()
{
    leDevice = await BluetoothLEDevice.FromIdAsync(device.Id);
    string selector = "(System.DeviceInterface.Bluetooth.DeviceAddress:=\"" +
         leDevice.BluetoothAddress.ToString("X") + "\")";
    var services = await leDevice.GetGattServicesAsync();
    foreach (var service in services.Services)
    { 
        switch (service.Uuid.ToString())
        {
        case SensorUUIDs.UUID_ENV_SERV:
            InitializeTemperatureSensor(service); 
            InitializePressureSensor(service); 
            break;
        case SensorUUIDs.UUID_ACC_SERV:
            InitializeAccelerationSensor(service);
            break;
        }
    }
    timer.Interval = new TimeSpan(0, 0, 1);
    timer.Tick += Timer_Tick;
    timer.Start();
}

You can see that we simple list all available services and once we found needed service we initialize appropriate sensor. This code should work even if you select a wrong device from the list of all BLE devices. The user interface will simply display nothing. Because two of our characteristics don’t support notifications we will simply use a timer to update the UI once per second.

The second method is exactly Tick implementation. It simply read data from all available sensors (characteristics) and uses INotifyPropertyChanged to update bindings:

public async void UpdateAllData()
{
    if (tempSensor != null)
    {
        temperature = String.Format(
            $"{(await tempSensor.GetTemperature())} Celsius");
        if (PropertyChanged!=null)
            PropertyChanged(this,
                new PropertyChangedEventArgs("Temperature"));
    } 
    if (presSensor != null)
    {
        pressure = String.Format(
            $"{(await presSensor.GetPressure()).ToString()} milliBar");
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs("Pressure"));
    }
    if (accSensor != null)
    {
        var data = await accSensor.GetAcceleration();
        angleX = data[0];
        angleY = data[1];
        angleZ = data[2];
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("AngleX"));
            PropertyChanged(this, new PropertyChangedEventArgs("AngleY"));
            PropertyChanged(this, new PropertyChangedEventArgs("AngleZ"));
        }
    }
}

Running our code, we will be able to see two tabs. On the first tab (Acceleration), you will be able to see data from the accelerometer:

clip_image010

The second tab provides information about temperature and pressure:

clip_image012

Now, you know how to connect your application to any BLE device and get data from there. At the same time, we didn’t pair out device. Let’s see, how to use Bluetooth API to implement pairing and get some benefits from there.

Written by Sergiy Baydachnyy

04/28/2017 at 4:10 AM