For a project I need to get some data from a Bluetooth device on windows 10 using C#. I'm not too familiar with the Bluetooth API and can't figure out why the following is not working:
Using the BluetoothLEAdvertisementWatcher I search for advertisements, which works fine. I do receive the advertisement from the device (local name fits) as well as it's ServiceUuids. Next I try to connect to the device using the BluetoothAddress received together with the advertisement:
private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher,
BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
ulong blAdress = eventArgs.BluetoothAddress;
BluetoothLEDevice blDevice = await
Windows.Devices.Bluetooth.BluetoothLEDevice.FromBluetoothAddressAsync(blAdress);
}
However, doing so results in an exception:
Element not found. (Exception from HRESULT: 0x80070490).
Is this the correct way to read data from the device? Are other options available to read the data from the services? Manually pairing the device in windows is not really an option and also seems to fail.
/Edit 1: I check for the local name of the device to make sure I only try to connect to the right one. So I guess there is a problem with connecting to this specific device, still I have no idea how to work around that. The service data was succesfully read on iOS, so it should be possible.
Until MS fixes this problem the only reliable solution to this I have found to connect to a BLE device is to ask the registry for a list of paired BLE devices and compare the bluetooth address in the advert with with registry list of paired able devices. My experience is that when FromBluetoothAddressAsync is called on an unpaired device Windows throws an exception and kills the watcher thread. I have some C++ code that I am happy to share that reads the registry and creates a list of paired BLE devices.
Hopefully MS will take the time to fully support BLE in the same manner Apple does.
Here is a reference from MS (https://social.msdn.microsoft.com/Forums/vstudio/en-US/e321cb3c-462a-4b16-b7e4-febdb3d0c7d6/windows-10-pairing-a-ble-device-from-code?forum=wdk). It seems that to use this BluetoothLEDevice.FromBluetoothAddressAsync we have to handle the exception when the device is advertising and not yet paired.
I got the same issue when I using the BluetoothLEAdvertisementWatcher directly.
Then I tested the different addresses listed by the watcher. I found it is related to the Bluetooth devices.
After adding the filter as following, I can connect to GATT device (TI Sensor Tag) successfully.
public sealed partial class MainPage : Page
{
private BluetoothLEAdvertisementWatcher watcher;
public MainPage()
{
this.InitializeComponent();
// Create and initialize a new watcher instance.
watcher = new BluetoothLEAdvertisementWatcher();
// Part 1B: Configuring the signal strength filter for proximity scenarios
// Configure the signal strength filter to only propagate events when in-range
// Please adjust these values if you cannot receive any advertisement
// Set the in-range threshold to -70dBm. This means advertisements with RSSI >= -70dBm
// will start to be considered "in-range".
watcher.SignalStrengthFilter.InRangeThresholdInDBm = -70;
// Set the out-of-range threshold to -75dBm (give some buffer). Used in conjunction with OutOfRangeTimeout
// to determine when an advertisement is no longer considered "in-range"
watcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -75;
// Set the out-of-range timeout to be 2 seconds. Used in conjunction with OutOfRangeThresholdInDBm
// to determine when an advertisement is no longer considered "in-range"
watcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(2000);
// By default, the sampling interval is set to zero, which means there is no sampling and all
// the advertisement received is returned in the Received event
// End of watcher configuration. There is no need to comment out any code beyond this point.
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
watcher.Received += OnAdvertisementReceived;
watcher.Stopped += OnAdvertisementWatcherStopped;
App.Current.Suspending += App_Suspending;
App.Current.Resuming += App_Resuming;
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
App.Current.Suspending -= App_Suspending;
App.Current.Resuming -= App_Resuming;
watcher.Stop();
watcher.Received -= OnAdvertisementReceived;
watcher.Stopped -= OnAdvertisementWatcherStopped;
base.OnNavigatingFrom(e);
}
private void App_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
// Make sure to stop the watcher on suspend.
watcher.Stop();
// Always unregister the handlers to release the resources to prevent leaks.
watcher.Received -= OnAdvertisementReceived;
watcher.Stopped -= OnAdvertisementWatcherStopped;
}
private void App_Resuming(object sender, object e)
{
watcher.Received += OnAdvertisementReceived;
watcher.Stopped += OnAdvertisementWatcherStopped;
}
private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
var address = eventArgs.BluetoothAddress;
BluetoothLEDevice device = await BluetoothLEDevice.FromBluetoothAddressAsync(address);
var cnt =device.GattServices.Count;
watcher.Stop();
}
/// <summary>
/// Invoked as an event handler when the watcher is stopped or aborted.
/// </summary>
/// <param name="watcher">Instance of watcher that triggered the event.</param>
/// <param name="eventArgs">Event data containing information about why the watcher stopped or aborted.</param>
private void OnAdvertisementWatcherStopped(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementWatcherStoppedEventArgs eventArgs)
{
}
private void start_Click(object sender, RoutedEventArgs e)
{
watcher.Start();
}
}
Just a guess, but maybe you need this:
watcher.ScanningMode = BluetoothLEScanningMode.Active;
and in the OnAdvertisementReceived event
if (e.AdvertisementType == BluetoothLEAdvertisementType.ScanResponse)
{
BluetoothLEDevice blDevice = await BluetoothLEDevice.FromBluetoothAddressAsync(e.BluetoothAddress);
}
If this is a UWP project, ensure you enable Bluetooth capabilities.
To do so in Visual Studio solution explorer double click the *.appxmanifest, choose the 'Capabilities' tab and ensure that 'Bluetooth' is checked.
It will add some xml not unlike the following;
<Capabilities>
<Capability Name="internetClientServer" />
<DeviceCapability Name="bluetooth" />
</Capabilities>
This Question is over 3 years old, but because it has over 13000 views, I will answer.
The reason for Element not found is that Windows.Devices is not aware of advertising Ble-devices until they are paired or connected.
Instead in the OnAdvertisementReceived just use:
var device = await BluetoothLEDevice.FromBluetoothAddressAsync(eventArgs.BluetoothAddress);
I also have a very simple uwp example on github, it has no controls to keep it as simple as possible. All the results are shown in the debug output window.
The most usefull info is in MainPage.xaml.cs
check it out: https://github.com/GrooverFromHolland/SimpleBleExample_by_Devicename
Related
Im trying to make a program that can scan for BLE advertisements. I have been looking at the Windows-universal-samples, more precisely the sample called BluetoothAdvertisement. I want to make a simple UWP application that can scan for BLE advertisements and show them in a listbox. But my application can't find anything at all and I'm totally lost.
namespace BleDiscAdv2
{
public sealed partial class MainPage : Page
{
// The Bluetooth LE advertisement watcher class is used to control and customize Bluetooth LE scanning.
private BluetoothLEAdvertisementWatcher watcher;
public MainPage()
{
this.InitializeComponent();
// Create and initialize a new watcher instance.
watcher = new BluetoothLEAdvertisementWatcher();
//Set the in-range threshold to -70dBm. This means advertisements with RSSI >= -70dBm
//will start to be considered "in-range"
watcher.SignalStrengthFilter.InRangeThresholdInDBm = -70;
// Set the out-of-range threshold to -75dBm (give some buffer). Used in conjunction with OutOfRangeTimeout
// to determine when an advertisement is no longer considered "in-range"
watcher.SignalStrengthFilter.OutOfRangeThresholdInDBm = -75;
// Set the out-of-range timeout to be 2 seconds. Used in conjunction with OutOfRangeThresholdInDBm
// to determine when an advertisement is no longer considered "in-range"
watcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(2000);
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
// Attach a handler to process the received advertisement.
// The watcher cannot be started without a Received handler attached
watcher.Received += OnAdvertisementReceived;
}
private void btStart_Click(object sender, RoutedEventArgs e)
{
watcher.Start();
}
private async void OnAdvertisementReceived(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
DateTimeOffset timestamp = eventArgs.Timestamp;
string localName = eventArgs.Advertisement.LocalName;
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
lbModtaget.Items.Add("Name of device: " + localName + "\t" + "Time for advertisement: " + timestamp.ToString("hh\\:mm\\:ss\\.fff"));
});
}
}
}
Can someone tell me what is wrong?
I'm new to BLE and I haven't been coding for a while.
Best regards
Christian
But my application can't find anything at all and I'm totally lost.
Please ensure that your app has enable Bluetooth capability in the Package.appxmanifest. See Basic Setup for details.
Please ensure the Bluetooth radio of running device was turn on and available.
There're devices are advertising and meet the filter. You can run the Scenario 2 of the Bluetooth advertisement official sample on another device to ensure that.
By testing on my side, your code snippet can scan the BLE advertisements well. In your code snippet, you didn't listen to the Stopped event handle of the watcher which is for notification to the app that the Bluetooth LE scanning for advertisements has been cancelled or aborted either by the app or due to an error. If the watcher is force stopped it will not get any advertisements.
You can add the Stopped event handle to check if there is a BluetoothError.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
// Attach a handler to process the received advertisement.
// The watcher cannot be started without a Received handler attached
watcher.Received += OnAdvertisementReceived;
watcher.Stopped += OnAdvertisementWatcherStopped;
}
private async void OnAdvertisementWatcherStopped(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementWatcherStoppedEventArgs args)
{
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
txtresult.Text = string.Format("Watcher stopped or aborted: {0}", args.Error.ToString());
});
}
For example, RadioNotAvailable may be caused by the running device is not enable the Bluetooth, OtherError may be caused by Bluetooth capability doesn't enabled. If the watcher is not stopped and there're advertisements, your app should work.
I am trying to create an app for learning purpose in which one windows phone 8 user sends the text and other user receives it. And the text is shared through NFC. But the problem is the other user is not able to receive the text.
Here is the code=>
Receiver's Code:
ProximityDevice device;
long subscribedMessageId;
private void receive_Click(object sender, RoutedEventArgs e)
{
device = ProximityDevice.GetDefault();
if (device != null)
{
subscribedMessageId = device.SubscribeForMessage("Windows.SampleMessage", messageReceivedHandler);
}
}
private void messageReceivedHandler(ProximityDevice sender, ProximityMessage message)
{
rtextbox.Text = message.DataAsString;
device.StopSubscribingForMessage(subscribedMessageId);
}
Sender's Code:
ProximityDevice device;
long publishedMessageId;
private void send_Click(object sender, RoutedEventArgs e)
{
device = ProximityDevice.GetDefault();
device.StopPublishingMessage(publishedMessageId);
if (device != null)
{
publishedMessageId = device.PublishMessage("Windows.SampleMessage", textbox1.Text);
textbox1.Text = "";
}
}
Both the codes are present on different page. Code is executed when the user clicks on send or receive button respectively.
I am new to NFC so any help will be appreciated.
Unfortunately, NFC gets complicated. There's quite a bit of plumbing involved to handle peer-to-peer communication seamlessly. It's far too much to put into an answer here on the site, so I will have to resort to links.
You can check out this Nokia article and project to work through your understanding of the plumbing and get an application going that will exchange text. http://developer.nokia.com/Resources/Library/Lumia/#!code-examples/nfc-talk.html
Then, if you want to take it up a notch, you can work through this article to upgrade your app to allow image transfer functionality as well. http://developer.nokia.com/Community/Wiki/Transfer_an_Image_with_NFC
I build a little script that checks if a USB Stick with a given Name ist plugged into the Computer, but now I want to build a service around this Script to watch if the Stick plugged in or not. At first I try to do this with the filewatcher and create a file on the Stick but if remove the stick from the pc and replugged the filewatcher dosent realize it. The following script check one time if the Stick is plugged in or not, but I need a script to loop this DriveInfo.GetDrive function. I dont know if the best way is to buil a 10 second timer loop around this function or if there is any watcher class for removeable devices in the .NET Framework. Here comes the Script:
public static void Main()
{
Run();
}
public static void Run()
{
var drives = DriveInfo.GetDrives()
.Where(drive => drive.IsReady && drive.DriveType == DriveType.Removable);
if (drives.Count() > 0)
{
foreach (var drive in drives)
{
if (drive.VolumeLabel == "TESTLABEL") Console.WriteLine("USB Stick is plugged in");
}
}
}
You can hook to (USB) Events using the ManagementEventWatcher.
Working example for LinqPad paraphrasing this neat answer which uses the Win32_DeviceChangeEvent:
// using System.Management;
// reference System.Management.dll
void Main()
{
using(var control = new USBControl()){
Console.ReadLine();//block - depends on usage in a Windows (NT) Service, WinForms/Console/Xaml-App, library
}
}
class USBControl : IDisposable
{
// used for monitoring plugging and unplugging of USB devices.
private ManagementEventWatcher watcherAttach;
private ManagementEventWatcher watcherDetach;
public USBControl()
{
// Add USB plugged event watching
watcherAttach = new ManagementEventWatcher();
watcherAttach.EventArrived += Attaching;
watcherAttach.Query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
watcherAttach.Start();
// Add USB unplugged event watching
watcherDetach = new ManagementEventWatcher();
watcherDetach.EventArrived += Detaching;
watcherDetach.Query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 3");
watcherDetach.Start();
}
public void Dispose()
{
watcherAttach.Stop();
watcherDetach.Stop();
//you may want to yield or Thread.Sleep
watcherAttach.Dispose();
watcherDetach.Dispose();
//you may want to yield or Thread.Sleep
}
void Attaching(object sender, EventArrivedEventArgs e)
{
if(sender!=watcherAttach)return;
e.Dump("Attaching");
}
void Detaching(object sender, EventArrivedEventArgs e)
{
if(sender!=watcherDetach)return;
e.Dump("Detaching");
}
~USBControl()
{
this.Dispose();// for ease of readability I left out the complete Dispose pattern
}
}
When attaching a USB-Stick I'll receive 7 attach (resp. detach) Events. Customize the Attaching/Detaching methods as you like. The blocking part is left to the reader, depending on his needs, with a Windows Service you wouldn't need to block at all.
I am developing a windows phone 7 app which is required to work with network.
I wanted my application to connect when NetworkAddress is changed that it becomes available. So I used NetworkChange.Networkaddresschanged. I was testing my app on emulator. It fires up first time but as there is no network I do nothing. This NetworkAddresschanged does not fire up the second time when network is available.
My code is
public void OnNetworkDownEvent()
{
lock (_networkChange)
{
var handler =_OnNetworkDown;
if (handler != null)
{
_OnNetworkDown();
}
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
NetworkChange.NetworkAddressChanged -= OnNetworkChange;
NetworkChange.NetworkAddressChanged += OnNetworkChange;
});
_connectionDown = true;
Monitor.Wait(_networkChange);
OnNetworkUpEvent();
}
}
public void OnNetworkUpEvent()
{
var handler = _OnNetworkUp;
if (handler != null)
{
_OnNetworkUp();
}
}
private void OnNetworkChange(object sender, EventArgs e)
{
lock(_networkChange)
{
if(NetworkInterface.GetIsNetworkAvailable())
{
if (_connectionDown)
{
_connectionDown = false;
Monitor.Pulse(_networkChange);
//OnNetworkUpEvent();
}
}
}
}
I call Networkdownevent() when network is down.And at that time I attach a delegate to NetworkAddressChange.
I do not know why this is happening.
The phone will see the USB connection to the host PC as it's primary connection so changes to the network connection of the attached PC will not have an impact on the phone.
This is one scenario where you can't test with the debugger attached. You'll have to store/display your debug output on the device with it not attached.
For testing I recommend having the phone connect to WiFi only and then controlling the connection state by turning the access point on or off. (This is the simplest technique I'm aware of for such a situation.)
Can someone give me a heads up... I'm trying to use the dotRAS .NET control, and this code to change the value of internetConnected (boolean) using an event handler...
But it seems that the state RasConnectionState.Disconnected is not triggered by dotRAS hangup()..
Any ideas? Am I doing it totally wrong... or have I managed to find a bug?
public class USBModem
{
// private vars
private RasDialer dialer = new RasDialer();
private bool internetConnected = false;
/// <summary>
/// Default constructor for USBModem
/// </summary>
public USBModem()
{
// Add Events for dialer
dialer.StateChanged += new EventHandler<StateChangedEventArgs>(dialer_StateChanged);
}
void dialer_StateChanged(object sender, StateChangedEventArgs e)
{
// Handle state changes here
switch (e.State)
{
case RasConnectionState.Connected:
internetConnected = true;
Console.WriteLine(e.State.ToString());
break;
case RasConnectionState.Disconnected:
internetConnected = false;
Console.WriteLine(e.State.ToString());
break;
default:
Console.WriteLine("INFO -> Unhandled state: " + e.State.ToString());
break;
}
}
public void ConnectInternet(string connectionName)
{
// Dial
dialer.PhoneBookPath = RasPhoneBook.GetPhoneBookPath(RasPhoneBookType.AllUsers);
dialer.EntryName = connectionName;
dialer.DialAsync();
}
public void DisconnectInternet()
{
foreach (RasConnection connection in dialer.GetActiveConnections())
{
connection.HangUp();
}
}
}
I've made some changes to the documentation for RasDialer in the 1.2 release to hopefully address this problem.
Apparently, a very simple (but widespread) mistake.
Basically the RasDialer component only handles events while a dialing operation is in progress.
The disconnected event would be raised if perhaps the modem line became unplugged during the connection attempt.
If you want to monitor client connections on the machine for connection/disconnection or a couple other events, use a RasConnectionWatcher. This will receive notifications from Windows when connection changes are made outside of a dialing operation.
Documentation on dotRAS is particularly sparse on Google... Head to http://dotras.codeplex.com for further information. The Help files included with the SDK are also very useful.