Connect to BLE peripheral on Windows 10 - windows

I try to connect to BLE peripheral. First, I watch for advertisements:
watcher = new BluetoothLEAdvertisementWatcher { ScanningMode = BluetoothLEScanningMode.Active };
watcher.Received += WatcherOnReceived;
watcher.Start();
and in the WatcherOnReceived callback I try to create BluetoothLEDevice
public async void WatcherOnReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs btAdv)
{
BluetoothLEDevice bleDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(btAdv.BluetoothAddress);
}
However, I always get bleDevice == null in WatcherOnReceived callback. Why and how to fix it? What is the proper way of creating BLE device in UWP application? I then need to connect to that device, discover its GATT services and characteristics, enable notifications on some of them and read/write some of them.

The answer to this question is simple - do not use BLE on Windows 10. The API doesn't work or behaves randomly and is totally undocumented. I like everyone talking about IoT being next industrial revolution and Microsoft not having working BLE API after 6 year BLE exists.

See example 8 and 9 in https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DeviceEnumerationAndPairing if you want to be able to connect to previously non-paired BLE devices, i.e. use a DeviceWatcher with a Bluetooth LE selector.
Otherwise you need to first pair it in the system's bluetooth pairing settings before you will be able to retrieve a BluetoothLEDevice from FromBluetoothAddressAsync.

You can check device information in WatcherOnReceived() to ensure that the device is what you want to connect with. Do it like this:
public async void WatcherOnReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs btAdv)
{
if (btAdv.Advertisement.LocalName == "SensorTag")
{
BluetoothLEDevice bleDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(btAdv.BluetoothAddress);
}
}
Use your own BLE device name instead of "SensorTag".
Note: You need pair your BLE device beforehand(either programatically like DeviceEnumerationAndPairing sample or PC's setting app as shown in the following image.).

Related

How to check internet connection one time i.e. not continuously?

I am building Xamarin.Forms app that pretty much works offline except a few calls to a web-service. Now I need to check internet connection just before I make a request, but I cannot find a solution or an answer that would allow checking internet connection only once not continuously
You could use Xamarin.Essentials and specifically Connectivity class as CrossConnectivity features have been consolidated into Xamarin.Essentials toolkit.
var connect = Connectivity.NetworkAccess;
if (connect != NetworkAccess.Internet) Message = "Device does not have internet access.";
else { // api call }
You can use the ConnectivityPlugin by James Montemagno
Nuget can be found here
For check the internet you just have to do this:
if(CrossConnectivity.Current.IsConnected)
{
//You are connected to the internet!!!
}
You might wanna check this: https://jamesmontemagno.github.io/ConnectivityPlugin/CheckingConnectivity.html
Xamarin Essentials Connectivity is also an option.
if (Connectivity.NetworkAccess == NetworkAccess.Internet)
{
//You are connected to the internet!!!
}

Android wifi and bluetooth scanning for location

Is there any intent to open the wifi and bluetooth scanning intent to ask the user to improve location accuracy?
UPDATE: I found a better way to ask directly the user to activate the Wifi Scanning doing this:
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (wifiManager.isScanAlwaysAvailable()==false) {
startActivity(new Intent(WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE));
}
So, my question now is: How can I do same thing to request scan always available for bluetooth? What Intent should I use?
The way to get to that screen is as follows:
For Nougat: Open Android settings, go to Location, 3 dots menu at top-right, Scanning.
For Oreo: Open Android settings, go to Security & Location, Location, Scanning
For Pie: Open Android settings, go to Location, Advanced, Scanning.
You can use the LocationSettingsRequest to prompt the user to enable location. In the request set builder.setNeedBle(true); to enable bluetooth scanning.
User will not be asked to enable bluetooth scanning if bluetooth is already switched on.
Continuously scanning for Bluetooth can affect your device performance
and battery life. So consider this under your own risk.
The code below keeps checking for the devices even after Discovery gets finished.
First, make sure you register the receiver by using
IntentFilter intentFilter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(myReceiver, intentFilter);
And try running the code.
private BluetoothAdapter mBtAdapter;
mBtAdapter.startDiscovery();
private final BroadcastReceiver mReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action))
{
//do something
}
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action))
{
Log.v(TAG,"Entered the Finished ");
mBtAdapter.startDiscovery();
}

Wifi WPS client start in Windows 10 in script or code

I can not find how to start WPS client in Windows 10 from command prompt or powershell. When I used Linux, everything was really ease with wla_supplicant (wpa_cli wps_pbc). Is there something similar in Windows?
Does anyone know how to set up Wi-Fi network (over WPS) key without human input in Windows?
I also tried WCN (Windows Connect Now) from Microsoft as it implements WPS features. I got also samples from Windows SDK on WCN, but they could not get key by WPS (it faild). But if I use Windows user interface to connect wiothout PIN, everyting seems to be pretty fine.
I am sure that there is possibility to do that, it is very important to perform Wifi Protected Setup by button start from the command prompt or app (C++/C#) without human intrusion or input (once WPS is on air, Windows should automatically get the network key and connect then).
I don't know if it's too late to answer, just put what I know in here and hope it can help.
First, if your system has updated to 16299(Fall Creator Update), you can just simply use new wifi api from UWP.
Install newest Windows SDK, create a C# console project, target C# version to at least 7.1, then add two reference to the project.
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETCore\v4.5\System.Runtime.WindowsRuntime.dll
C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.16299.0\Windows.winmd
After all of that , code in below should work.
using System;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.WiFi;
class Program
{
static async Task Main(string[] args)
{
var dic = await DeviceInformation.FindAllAsync(WiFiAdapter.GetDeviceSelector());
if (dic.Count > 0)
{
var adapter = await WiFiAdapter.FromIdAsync(dic[0].Id);
foreach (var an in adapter.NetworkReport.AvailableNetworks)
{
if (an.Ssid == "Ssid which you want to connect to.")
{
// Fouth parameter which is ssid can not be set to null even if we provided
// first one, or an exception will be thrown.
await adapter.ConnectAsync(an, WiFiReconnectionKind.Manual, null, "",
WiFiConnectionMethod.WpsPushButton);
}
}
}
}
}
Build and run the exe, then push your router's button, your pc will be connect to the router.
But if you can not update to 16299, WCN will be your only choice. You may already notice that if call IWCNDevic::Connect frist with push-button method, the WSC(Wifi Simple Configuration) session will fail. That's because WNC would not start a push-button session as a enrollee, but only as a registrar. That means you have to ensure that router's button has been pushed before you call IWCNDevic::Connect. The way to do that is using Native Wifi api to scan your router repeatedly, analyse the newest WSC information element from the scan result, confirm that Selected Registrar attribute has been set to true and Device Password Id attribute has been set to 4. After that, query the IWCNDevice and call Connect function will succeed. Then you can call IWCNDevice::GetNetworkProfile to get a profile that can use to connect to the router. Because it's too much of code, I will only list the main wifi api that will be used.
WlanEnuminterfaces: Use to get a available wifi interface.
WlanRegisterNotification: Use to register a callback to handle scan an connect results.
WlanScan: Use to scan a specified wifi BSS.
WlanGetNetworkBsslist: Use to get newest BSS information after scan.
WlanSetProfile: Use to save profile for a BSS.
WlanConnect: Use to connect to a BSS.
And about the WSC information element and it's attributes, you can find all the information from Wi-Fi Simple Configuration Technical Specification v2.0.5.
For Krisz. About timeout.
You can't cast IAsyncOperation to Task directly. The right way to do that is using AsTask method. And also, you should cancel ConnectAsync after timeout.
Sample code:
var t = adapter.ConnectAsync(an, WiFiReconnectionKind.Manual, null, "",
WiFiConnectionMethod.WpsPushButton).AsTask();
if (!t.Wait(10000))
t.AsAsyncOperation().Cancel();

restrict the windows phone app for specific devices

i want my application should work on specific devices\OS like "Lumia 650"\"windows phone 8", this is my project requirement.
Is it possible ? if yes where should I mention the details ?
It is not a problem to restrict Windows Phone 8. You just need to build it targeting Windows Phone OS 8.0.
For the device model you do something like this in the App.xaml.cs
private void Application_Launching(object sender, LaunchingEventArgs e)
{
var deviceName = DeviceExtendedProperties.GetValue("DeviceName").ToString();
if (!deviceName.Contains("Lumia_650")) // Please check your phone's actual value
Application.Current.Terminate();
}
If you want to show a friendly message before it exits you can move the code to the MainPage.xaml.cs then add the MessageBox.Show(message) part.
This is only possible in code as you can not prevent users from installing the app if the app is meant for that particular OS what that user has. However, once the app is launched you can get the name of the device and do actions accordingly.
You can try this:
var PhoneName = Microsoft.Phone.Info.DeviceStatus.DeviceName;
if(PhoneName == "Not Allowed Phone")
{
MessageBox.Show("You can not use this app");
}
else
{
}

Windows bluetooth autopairing or disable authentication

I need windows to automatically pair with bluetooth devices. I don't want the user to have to click anything on the windows side. The server will be physically located somewhere the user cannot get to. Having to pair on the user side is fine. Windows just needs to accept any requests that come in without user input.
How can I accomplish this? Registry hacks? Replace a dll? A Hardware change (autopairing dongle or something)?
Is there any SDK that will give me the tools take care of this?
Currently I am using bluecove on the windows machine on top of Microsoft stack. I tried the Widcomm stack also with no luck.
The primary protocol that devices will use to connect is RFCOMM.
EDIT:
using the accepted answer below I came up with this code, that auto-pairs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using InTheHand.Net.Bluetooth;
using System.Threading;
namespace BT
{
class BluetoothAutoSSP
{
public static void Main()
{
BluetoothAutoSSP c = new BluetoothAutoSSP();
EventHandler<BluetoothWin32AuthenticationEventArgs> handler = new EventHandler<BluetoothWin32AuthenticationEventArgs>(c.handleRequests);
BluetoothWin32Authentication authenticator = new BluetoothWin32Authentication(handler);
while (true)
{
Thread.Sleep(10);
}
}
public void handleRequests(Object thing, BluetoothWin32AuthenticationEventArgs args)
{
args.Confirm = true;
}
}
}
For the Microsoft Bluetooth stack: To support both traditional Bluetooth pairing as well as v2.1's Secure Simple Pairing use the BluetoothRegisterForAuthenticationEx function and in your callback function respond by calling BluetoothSendAuthenticationResponseEx.
See more at BluetoothWin32Authentication 32feet.NET docs which describes the way to handle that in the 32feet.NET Bluetooth library for .NET, my doc Bluetooth in Windows 7, and MSDN e.g. BluetoothRegisterForAuthenticationEx etc.
BTW Widcomm does not have a programatic way to respond to pairing (it does have a method to initiate pairing). BlueSoleil does have an API apparently.

Resources