In my windows forms app I am starting to enumerate list of devices as follows:
DeviceWatcher deviceWatcher =
DeviceInformation.CreateWatcher(
BluetoothLEDevice.GetDeviceSelectorFromPairingState(false),
requestedProperties,
DeviceInformationKind.AssociationEndpoint);
// Register event handlers before starting the watcher.
// Added, Updated and Removed are required to get all nearby devices
deviceWatcher.Added += DeviceWatcher_Added;
// EnumerationCompleted and Stopped are optional to implement.
deviceWatcher.EnumerationCompleted += DeviceWatcher_EnumerationCompleted;
deviceWatcher.Stopped += DeviceWatcher_Stopped;
// Start the watcher.
deviceWatcher.Start();
when a device is found I am retrieving the service and characteristic as follows:
BluetoothLEDevice btdev;
List<DeviceInformation> lst = new List<DeviceInformation>();
GattCharacteristic ch;
private async void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
{
if (args.Name == "Bluno")
{
btdev = await BluetoothLEDevice.FromIdAsync(args.Id);
GattDeviceServicesResult result = await btdev.GetGattServicesAsync();
Guid customGuid = new Guid("0000dfb0-0000-1000-8000-00805f9b34fb");
foreach (GattDeviceService service in result.Services)
{
if (customGuid == service.Uuid)
{
GattCharacteristicsResult cresult = await service.GetCharacteristicsAsync();
ch = cresult.Characteristics.Where(x => x.Uuid == new Guid("0000dfb1-0000-1000-8000-00805f9b34fb")).FirstOrDefault();
ch.ValueChanged += Ch_ValueChanged;
}
}
}
}
the issue is that it is not firing the ValueChanged event even if the BLE device continuously sending multiple values per second.
help appreciated
Related
I want to be able to send and receive data over a socket using bluetooth when my app is suspended. I register my BackgroundReader once a connection is established in the foreground app.
Code run once a connection is established:
private void OnConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
BackgroundTaskRegistration receiveTask = RegisterBackgroundTask("X.ReceiverTask", "ReceiverTask", new SocketActivityTrigger(), null);
BackgroundTaskRegistration sendTask = RegisterBackgroundTask("X.Z", "SenderTask", new ApplicationTrigger(), null);
var socket = args.Socket;
socket.EnableTransferOwnership(receiveTask.TaskId, SocketActivityConnectedStandbyAction.DoNotWake);
socket.TransferOwnership("RfcommSocket");
}
Method to register a Background task:
private static BackgroundTaskRegistration RegisterBackgroundTask(string taskEntryPoint, string name, IBackgroundTrigger trigger, IBackgroundCondition condition)
{
foreach(var cur in BackgroundTaskRegistration.AllTasks)
{
if(cur.Value.Name == name)
{
//task is already registered
return (BackgroundTaskRegistration)(cur.Value);
}
}
var builder = new BackgroundTaskBuilder();
builder.Name = name;
if(taskEntryPoint != null && taskEntryPoint != String.Empty)
{
builder.TaskEntryPoint = taskEntryPoint;
}
builder.SetTrigger(trigger);
if(condition != null)
{
builder.AddCondition(condition);
}
BackgroundTaskRegistration task = builder.Register();
return task;
}
When I try to send data the Receiver background task activates as expected. Only when I try to read the stream socket from its properties, it returns null and throws an Exception when I try to access it:
public async void Run(IBackgroundTaskInstance taskInstance)
{
taskDeferral = taskInstance.GetDeferral();
taskInstance.Canceled += OnTaskCanceled;
var details = taskInstance.TriggerDetails as SocketActivityTriggerDetails;
var socketInformation = details.SocketInformation;
switch (details.Reason)
{
...
case SocketActivityTriggerReason.SocketActivity:
Debug.WriteLine(socketInformation.SocketKind.ToString());
var socket = socketInformation.StreamSocket; //This returns null
DataReader reader = new DataReader(socket.InputStream);
reader.InputStreamOptions = InputStreamOptions.Partial;
await reader.LoadAsync(250);
var dataString = reader.ReadString(reader.UnconsumedBufferLength);
Debug.WriteLine(dataString);
socket.TransferOwnership(socketInformation.Id); /* Important! */
break;
...
}
taskDeferral.Complete();
}
The backgroundTaskHost.exe exits and, supposedly, takes the socket with it.
Thanks in advance!
Backgroundtask is activated by SocketActivityTrigger, but the socket in the trigger returns null
I checked your code, The problem is you used SocketActivityTrigger in Bluetooth RF communication. In UWP we often use RfcommConnectionTrigger to detect Bluetooth message notification. The RfcommConnectionTrigger has more features that support Bluetooth RF communication. And I have test with official code sample and it could get the socket instance correctly and could load the message with reader.
I am just trying to connect my device to cloud using Azure IOT Hub. But I am getting an error as below.
MessagingEntityNotFoundException: The messaging entity 'ihsuprodsgres029dednamespace:eventhub:iothub-ehub-' could not be found. TrackingId:4772b610-8ff3-4709-8ea9-ffcd5784fe1c_B4, SystemTracker:ihsuprodsgres029dednamespace:eventhub:iothub-ehub-sibeeshiot-176205-a588b66686~16383|team01, Timestamp:6/23/2017 3:07:54 PM TrackingId:41110b704d814af497fd9924da6714d8_G4, SystemTracker:gateway2, Timestamp:6/23/2017 3:07:55 PM, referenceId: 41110b704d814af497fd9924da6714d8_G4
Can you please help me with it, if you have ever faced the same issue. Below is the code I am trying.
static void Main(string[] args) {
Console.WriteLine("Receive messages. Ctrl-C to exit.\n");
eventHubClient = EventHubClient.CreateFromConnectionString(connectionString, iotHubD2cEndpoint);
var d2cPartitions = eventHubClient.GetRuntimeInformation().PartitionIds;
CancellationTokenSource cts = new CancellationTokenSource();
System.Console.CancelKeyPress += (s, e) = >{
e.Cancel = true;
cts.Cancel();
Console.WriteLine("Exiting...");
};
var tasks = new List < Task > ();
foreach(string partition in d2cPartitions) {
tasks.Add(ReceiveMessagesFromDeviceAsync(partition, cts.Token));
}
Task.WaitAll(tasks.ToArray());
}
private static async Task ReceiveMessagesFromDeviceAsync(string partition, CancellationToken ct) {
var eventHubReceiver = eventHubClient.GetConsumerGroup("Team01").CreateReceiver(partition, DateTime.UtcNow);
while (true) {
if (ct.IsCancellationRequested) break;
EventData eventData = await eventHubReceiver.ReceiveAsync();
if (eventData == null) continue;
string data = Encoding.UTF8.GetString(eventData.GetBytes());
Console.WriteLine("Message received. Partition: {0} Data: '{1}'", partition, data);
}
}
It looks like your iotHubD2cEndpoint value is not correct Event Hub-compatible name (probably you are using the messages/events such as an Azure IoT Hub Endpoint).
The following screen snippet shows the Event Hub compatible endpoint for Events:
The other option is to use an Azure IoT Hub Connection string and Endpoint Events, see the following example:
iotHubD2cEndpoint = "messages/events"
connectionString = "HostName=*****.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=******"
I would like to keep on reading characteristic/set value changed event handlers for characteristics from my BLE 4.0 device, by using the ValueChanged callback in Universal Windows Platform C# in Visual Studio 2017.
I followed some tutorial from these sites: Damian Blog's Windows Universal with BLE, Bluetooth Gatt's Git Hub, Bluetooth Generic Attribute Profile - Heart Rate Service and Dr. Jukka's mobile Blog on BLE. All of them are using ValueChanged and I have tried to follow what they did.
Unfortunately, instead of ValueChanged being triggered, I receive the following error when using the ValueChanged callback.
System.ArgumentException: 'Value does not fall within the expected range.'
This line of code is producing the error:
characteristic.ValueChanged += Oncharacteristic_ValueChanged;
Here is more details of my source code:
NOTE: I am using COM 7 for my dongler and my program could discover the BLE's device name, and could discover the Uuid of the services and characteristics.
public List<string> serviceList = new List<string>();
public List<string> characteristicList = new List<string>();
public BluetoothLEDevice myDevice { get; set; }
public MainPage()
{
this.InitializeComponent();
}
private async void Page_Loaded(object sender, RoutedEventArgs e)
{
// Find the com port
string selector = SerialDevice.GetDeviceSelector("COM7");
DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(selector);
if (devices.Count > 0)
{
var dialog = new MessageDialog("Com Device found");
await dialog.ShowAsync();
DeviceInformation deviceInfo = devices[0];
SerialDevice serialDevice = await SerialDevice.FromIdAsync(deviceInfo.Id);
serialDevice.BaudRate = 9600;
serialDevice.DataBits = 8;
serialDevice.StopBits = SerialStopBitCount.One;
serialDevice.Parity = SerialParity.None;
}
else
{
MessageDialog popup = new MessageDialog("Sorry, no device found.");
await popup.ShowAsync();
}
// After com port is found, search for device
foreach (DeviceInformation di in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelector()))
{
BluetoothLEDevice bleDevice = await BluetoothLEDevice.FromIdAsync(di.Id);
// Display BLE device name
var dialogBleDeviceName = new MessageDialog("BLE Device Name " + bleDevice.Name);
await dialogBleDeviceName.ShowAsync();
myDevice = bleDevice;
}
// Check device connection
myDevice.ConnectionStatusChanged += OnConnectionStatusChanged;
foreach (var service in myDevice.GattServices)
{
serviceList.Add(service.Uuid.ToString());
// Verify if service is discovered by displaying a popup
MessageDialog serviceUuidPopUp = new MessageDialog("Adding Service Uuid to list " + service.Uuid.ToString() );
await serviceUuidPopUp.ShowAsync();
foreach (var characteristic in service.GetAllCharacteristics())
{
var characteristicUuid = characteristic.Uuid.ToString().ToLowerInvariant();
characteristicList.Add(characteristicUuid);
// Verify if characteristic is discovered by displaying a popup
MessageDialog charUuidPopUp = new MessageDialog("Adding characteristic Uuid to list " + characteristicUuid);
await charUuidPopUp.ShowAsync();
// set value changed event handlers for characteristics
characteristic.ValueChanged += Oncharacteristic_ValueChanged;
}
}
}
private void OnConnectionStatusChanged(BluetoothLEDevice sender, object args)
{
if (sender.ConnectionStatus == BluetoothConnectionStatus.Connected)
{
System.Diagnostics.Debug.WriteLine("Connected");
}
else
{
System.Diagnostics.Debug.WriteLine("Disconnected");
}
}
private void Oncharacteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
byte[] data = new byte[args.CharacteristicValue.Length];
DataReader.FromBuffer(
args.CharacteristicValue).ReadBytes(data);
string text = Encoding.UTF8.GetString(data, 0, data.Length);
}
UPDATE 1
I tried to check Characteristic Properties before set value changed event handlers for my characteristics by following the answer given by rudi belt on SO.
if (characteristic.CharacteristicProperties == (GattCharacteristicProperties.Read | GattCharacteristicProperties.Notify))
{
characteristic.ValueChanged += Oncharacteristic_ValueChanged;
}
Unfortunately, this IF statement is not executed.
UPDATE 2
I have tried to remove ALL the codes inside Oncharacteristic_ValueChanged method. But it still gives me the same error
System.ArgumentException: 'Value does not fall within the expected range.'
I have been spending a lot of time trying to solve this problem. I will be very happy if anyone can help me on this. Thank you!
Reading your efforts in the former question I can provide a working example, but first some explanation.
myDevice.ConnectionStatusChanged is not needed, it is only used to notice a connection is lost or connected. You have to connect to your device first and handle things in the connection method.
After you have succeeded in connecting you have to get the service that contains the characteristic you want to use for read, write, notify or indicate.
When you have selected the service You can get the characteristics of that service.
Select the characteristic by Uuid, or in my example with CharacteristicProperties.HasFlag.
This flag in my example is Notify.
In the code comments you find extra info.
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
using Windows.UI.Popups;
using Windows.UI.Xaml.Controls;
namespace App1
{
public sealed partial class MainPage : Page
{
GattDeviceServicesResult serviceResult = null;
private BluetoothLEDevice myDevice;
private GattCharacteristic selectedCharacteristic;
public MainPage()
{
this.InitializeComponent();
ConnectDevice();
}
private async void ConnectDevice()
{
//This works only if your device is already paired!
foreach (DeviceInformation di in await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelector()))
{
BluetoothLEDevice bleDevice = await BluetoothLEDevice.FromIdAsync(di.Id);
// Display BLE device name
var dialogBleDeviceName = new MessageDialog("BLE Device Name " + bleDevice.Name);
await dialogBleDeviceName.ShowAsync();
myDevice = bleDevice;
}
if (myDevice != null)
{
int servicesCount = 3;//Fill in the amount of services from your device!!!!!
int tryCount = 0;
bool connected = false;
while (!connected)//This is to make sure all services are found.
{
tryCount++;
serviceResult = await myDevice.GetGattServicesAsync();
if (serviceResult.Status == GattCommunicationStatus.Success && serviceResult.Services.Count >= servicesCount)
{
connected = true;
Debug.WriteLine("Connected in " + tryCount + " tries");
}
if (tryCount > 5)//make this larger if faild
{
Debug.WriteLine("Failed to connect to device ");
return;
}
}
if (connected)
{
for (int i = 0; i < serviceResult.Services.Count; i++)
{
var service = serviceResult.Services[i];
//This must be the service that contains the Gatt-Characteristic you want to read from or write to !!!!!!!.
string myServiceUuid = "0000ffe0-0000-1000-8000-00805f9b34fb";
if (service.Uuid.ToString() == myServiceUuid)
{
Get_Characteriisics(service);
break;
}
}
}
}
}
private async void Get_Characteriisics(GattDeviceService myService)
{
var CharResult = await myService.GetCharacteristicsAsync();
if (CharResult.Status == GattCommunicationStatus.Success)
{
foreach (GattCharacteristic c in CharResult.Characteristics)
{
if (c.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify))
{
selectedCharacteristic = c;
break;
}
}
try
{
// Write the ClientCharacteristicConfigurationDescriptor in order for server to send notifications.
var result = await selectedCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(
GattClientCharacteristicConfigurationDescriptorValue.Notify);
if (result == GattCommunicationStatus.Success)
{
var dialogNotifications = new MessageDialog("Successfully registered for notifications");
await dialogNotifications.ShowAsync();
selectedCharacteristic.ValueChanged += SelectedCharacteristic_ValueChanged;
}
else
{
var dialogNotifications = new MessageDialog($"Error registering for notifications: {result}");
await dialogNotifications.ShowAsync();
}
}
catch (Exception ex)
{
// This usually happens when not all characteristics are found
// or selected characteristic has no Notify.
var dialogNotifications = new MessageDialog(ex.Message);
await dialogNotifications.ShowAsync();
await Task.Delay(100);
Get_Characteriisics(myService); //try again
//!!! Add a max try counter to prevent infinite loop!!!!!!!
}
}
else
{
var dialogNotifications = new MessageDialog("Restricted service. Can't read characteristics");
await dialogNotifications.ShowAsync();
}
}
private void SelectedCharacteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
{
}
}
}
If you have problems with this code feel free to ask in comments.
I try to send iOS push notifications using pushsharp library but I got
the maximum send attempts was reached
This is my code (note that I'm implementing pushbroker event function but I'm not showing it here):
public class PushNotificationApple
{
private static PushBroker _pushBroker;
public PushNotificationApple()
{
if (_pushBroker == null)
{
//Create our push services broker
_pushBroker = new PushBroker();
_pushBroker.OnNotificationSent += NotificationSent;
_pushBroker.OnChannelException += ChannelException;
_pushBroker.OnServiceException += ServiceException;
_pushBroker.OnNotificationFailed += NotificationFailed;
_pushBroker.OnDeviceSubscriptionExpired += DeviceSubscriptionExpired;
_pushBroker.OnDeviceSubscriptionChanged += DeviceSubscriptionChanged;
_pushBroker.OnChannelCreated += ChannelCreated;
_pushBroker.OnChannelDestroyed += ChannelDestroyed;
PushBroker broker = new PushBroker();
string certpass = "XXXXXX.";
var appleCert = File.ReadAllBytes("c:\\certifIOS\\Certificates.p12");
_pushBroker.RegisterAppleService(new ApplePushChannelSettings(false, appleCert, certpass)); //Extension method
}
}
public void SendNotification(string deviceToken, string message)
{
//Fluent construction of an iOS notification
//IMPORTANT: For iOS you MUST MUST MUST use your own DeviceToken here that gets generated within your iOS app itself when the Application Delegate
// for registered for remote notifications is called, and the device token is passed back to you
if (_pushBroker != null)
{
AppleNotification appnotif = new AppleNotification() ;
_pushBroker.QueueNotification(appnotif
.ForDeviceToken(deviceToken)//the recipient device id
.WithAlert(message)//the message
.WithBadge(1)
.WithSound("default")
);
bool v = appnotif.IsValidDeviceRegistrationId();
_pushBroker.StopAllServices(true);
}
}
}
Most likely the connections to apple push gateways are blocked,please try to use telnet:
telnet gateway.push.apple.com 2195
telnet gateway.sandbox.push.apple.com 2195
make sure they are not blocked
Afternoon all,
I have a windows service which subscribes to an Office365 email account and awaits new emails, when they arrive it processes their attachments, and all is well with the world.
But... for some reason, the applications stops receiving notifications after an undetermined amount of time.
I have handled the 'OnDisconnect' event and reestablish a connection as shown in the below code, but that doesnt seem to be fixing this issue. The windows service continues to run fine, and if I restart the service everything is good again, until is failed again.
This is the my class for running exchange:
public class ExchangeConnection
{
static readonly ExchangeService Service = Exchange.Service.ConnectToService(UserDataFromConsole.GetUserData(), new TraceListener());
public event EmailReceivedHandler OnEmailReceived;
public ExchangeConnection()
{
}
public void Open()
{
SetStreamingNotifications(Service);
var signal = new AutoResetEvent(false);
signal.WaitOne();
}
private void SetStreamingNotifications(ExchangeService service)
{
var streamingsubscription = service.SubscribeToStreamingNotifications(new FolderId[] { WellKnownFolderName.Inbox }, EventType.NewMail);
var connection = new StreamingSubscriptionConnection(service, 30);
connection.AddSubscription(streamingsubscription);
connection.OnNotificationEvent += OnEvent;
connection.OnSubscriptionError += OnError;
connection.OnDisconnect += OnDisconnect;
connection.Open();
}
public void MoveEmail(ItemId id, String folderName = "Archived Emails")
{
var rootFolder = Folder.Bind(Service, WellKnownFolderName.Inbox);
var archivedFolder = rootFolder.FindFolders(new FolderView(100)).FirstOrDefault(x => x.DisplayName == folderName);
if (archivedFolder == null)
{
archivedFolder = new Folder(Service) { DisplayName = folderName };
archivedFolder.Save(WellKnownFolderName.Inbox);
}
Service.MoveItems(new List<ItemId> {id}, archivedFolder.Id);
}
#region events
private void OnDisconnect(object sender, SubscriptionErrorEventArgs args)
{
//The connection is disconnected every 30minutes, and we are unable to override this,
//so when we get disconnected we just need to reconnect again.
var connection = (StreamingSubscriptionConnection)sender;
connection.Open();
}
private void OnEvent(object sender, NotificationEventArgs args)
{
var subscription = args.Subscription;
// Loop through all item-related events.
foreach (var notification in args.Events)
{
switch (notification.EventType)
{
case EventType.NewMail:
if (notification is ItemEvent)
{
var email = Item.Bind(Service, new ItemId(((ItemEvent) notification).ItemId.UniqueId));
OnEmailReceived(new EmailReceivedArgs((EmailMessage)email));
}
break;
}
}
}
private void OnError(object sender, SubscriptionErrorEventArgs args)
{
var e = args.Exception;
Logger.LogException(e,LogEventType.Error);
}
#endregion events
}
Any help would be great, thanks.
EDIT:
After improving the error logging I have found this exception occuring:
Exception: The specified subscription was not found.
Any ideas what is causing this?
With Office365 you need to make sure you deal with affinity see http://msdn.microsoft.com/en-us/library/office/dn458789(v=exchg.150).aspx . Adding those headers will ensure your requests will always routed to the correct servers.
Cheers
Glen