I'm trying to create a background task that will be run when the system detects an eddystone advertisement broadcasted by an estimote beacon.
I already configured the beacon to send eddystone packets and I used UniversalBeaconLibrary to get these packets while the application is in the foreground (no problems here).
Now I want to get a notification while the application is not launched (using a background task reacting to bluetooth broadcasted packets). To my understanding, to avoid putting to much strain on the battery/cpu, I do need to filter these advertisements.
One of the simplest form of filtering (the one I tried to use) is by using the company id given by the Bluetooth SIG.
Here is what I tried :
public static async void Register()
{
if (BackgroundTaskRegistration.AllTasks.Count == 0)
{
var trigger = MakeTrigger();
// this is needed for Phone, not so for Windows in this case.
var allowed = await BackgroundExecutionManager.RequestAccessAsync();
if ((allowed != BackgroundAccessStatus.Denied) &&
(allowed != BackgroundAccessStatus.Unspecified))
{
BackgroundTaskBuilder builder = new BackgroundTaskBuilder
{
Name = "BLEWatcher",
TaskEntryPoint = typeof(BLEBackgroundConsumer.Consumer).FullName
};
builder.SetTrigger(trigger);
builder.Register();
}
}
}
private static BluetoothLEAdvertisementWatcherTrigger MakeTrigger()
{
var trigger = new BluetoothLEAdvertisementWatcherTrigger();
//Can add some filters here
//trigger.AdvertisementFilter.Advertisement.ManufacturerData.Add(new BluetoothLEManufacturerData()
//{
// CompanyId = 349 //Estimote
//});
//trigger.AdvertisementFilter.Advertisement.ManufacturerData.Add(new BluetoothLEManufacturerData()
//{
// CompanyId = 76 // Apple
//});
//trigger.AdvertisementFilter.Advertisement.ManufacturerData.Add(new BluetoothLEManufacturerData()
//{
// CompanyId = 224 // Google
//});
return (trigger);
}
As it is I get an exception, saying that there is not enough or too much filtering.
When uncommenting one of the trigger blocks, I got no exception but the task does not seem to launch.
**EDIT : ** I asked estimote what was the Company Id they were boradcasting when using eddystone packets. And according to them there is none.
In regard of this answer, what would be a suitable filter ?
A Bluetooth SIG company id is only used with a manufacturer Bluetooth LE advertisement, like iBeacon and AltBeacon. Eddystone uses service Bluetooth LE advertisements, which don't contain a company id. Instead, they contain a 16-bit Service UUID of 0xFEAA.
See here for more details: https://github.com/google/eddystone/blob/master/protocol-specification.md
Related
I'm developing a c# desktop api with forms where I want to receive ACC data from a BLE server und display them in a chart.
So I'm running in a connection problem and I can't find any solution.
I can find my LE server Device with the watcher.
DevicePairingResult dpr = await device.DeviceInformation.Pairing.PairAsync(DevicePairingProtectionLevel.Encryption);
returns me "AlreadyPaired"
But when I do
device = await BluetoothLEDevice.FromBluetoothAddressAsync(bluetoothAddress: eventArgs.BluetoothAddress);
mGattService = device.GetGattService(MotionService_GUID);
mCharacteristic = mGattService.GetCharacteristics(ACC_Characteristic_GUID)[0];
and then
var con = device.ConnectionStatus;
I receive "Disconnected" in con.
I am bound with de device on windows( I searched for it in Windows and entered the Code) but I am not connected(based on the Status in the windows info center).
I've read in another Thread in the windows c# developer page that it should not be necessary anymore to pair the device manually.
I'm pretty shure that the rest of my code works because sometimes I can get a connection( pretty confusing for me) and see the right Data in my chart.
Right now I just want to reach a stable connection before changing other part of my code.
Anyone any idea how to solve this?
Thx medTech
Edit:
Here is part of the Code:
Scanning for BLE
private void button1_Click(object sender, EventArgs e)
{
// Create Bluetooth Listener
var watcher = new BluetoothLEAdvertisementWatcher();
watcher.ScanningMode = BluetoothLEScanningMode.Active;
// Register callback for when we see an advertisements
watcher.Received += OnAdvertisementReceivedAsync;
// Wait 5 seconds to make sure the device is really out of range
watcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000);
watcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000);
// Starting watching for advertisements
watcher.Start();
}
Connect to Server:
private async void OnAdvertisementReceivedAsync(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
// Filter for specific Device
if (eventArgs.Advertisement.LocalName == "MYDEVICE")
{
watcher.Stop();
var MotionService_GUID = new Guid("00002000-0000-1000-8000-00805F9B34FB");
var ACC_Characteristic_GUID = new Guid("00002001-0000-1000-8000-00805F9B34FB");
device = await BluetoothLEDevice.FromBluetoothAddressAsync(bluetoothAddress: eventArgs.BluetoothAddress);
DevicePairingResult dpr = await device.DeviceInformation.Pairing.PairAsync(DevicePairingProtectionLevel.Encryption);
mGattService = device.GetGattService(MotionService_GUID);
mCharacteristic = mGattService.GetCharacteristics(ACC_Characteristic_GUID)[0];
GattDeviceServicesResult result = await device.GetGattServicesAsync();
GattCommunicationStatus status1 = await ReadFromCharacteristicAsync(mCharacteristic);
var con = device.ConnectionStatus;
while (status1 == GattCommunicationStatus.Success)
{
try
{
status1 = await ReadFromCharacteristicAsync(mCharacteristic);
}
catch
{
Console.WriteLine("ERROR");
status1 = GattCommunicationStatus.Unreachable;
}
}
}
}
Read from Characteristic:
async Task ReadFromCharacteristicAsync(GattCharacteristic mCharacteristic)
{
GattReadResult readResult = await mCharacteristic.ReadValueAsync(BluetoothCacheMode.Uncached);
if (readResult.Status == GattCommunicationStatus.Success)
{
byte[] data = new byte[readResult.Value.Length];
DataReader.FromBuffer(readResult.Value).ReadBytes(data);
if (chart1.IsHandleCreated)
{
this.Invoke((MethodInvoker)delegate { updateChart(data); });
}
return readResult.Status;
}
return readResult.Status;
}
Terminate Connection
private async Task<bool> ClearBluetoothLEDeviceAsync()
{
mCharacteristic.Service.Dispose();
mGattService.Dispose();
await device.DeviceInformation.Pairing.UnpairAsync();
device?.Dispose();
device = null;
GC.Collect();
return true;
}
SO now when I connect the first time to the Server, I only receive zeros which shows me that the there might be a authentication Error.
After that I always receive this Error:
"System.ArgumentException" in mscorlib.dll with a notification that there is noch executable Code left because all Threads are doing some asynchronous stuff.
This Error gets thrown when I try to read from the Characteristic.
I never coded in c# before so I am not shure if there is an error in my asynchronous part oder the communication part.
Thanks you
Pairing is not the same as connecting!
I really advise using the BLE-advertisementWatcher to select and connect to your device.
The reason is that many BLE-devices don't save their pairing status.
In windows device-watcher once paired, the device stays paired even if it is switched off or out of reach.
Also many times the connection status is kept, unless the device is unpaired and disposed in code or removed in windows settings.
All BLE-devices that I know of start advertising as soon as there is no connection for some time.
This time depends on the device, but most of the time within seconds.
So don't pair but just connect if the device is advertising.
I've been trying to implement a BackgroundTask for Raw Push Notifications on my Windows and Windows Phone 8.1 apps but it doesn't seem to be working. I've successfully managed to get toast based push notifications working but as far as I'm aware a Raw notification silently pushes data to the app and it's up to the app to display a toast notification or update the app's tile.
I've looked at the BackgroundTask Sample and followed it exactly yet nothing works (https://code.msdn.microsoft.com/windowsapps/Background-Task-Sample-9209ade9).
Here's the steps I've taken
Created a Windows Runtime Component Project in the same solution as my other projects (Called NotificationServer)
Renamed the class to RawTask.cs and implemented IBackgroundTask and its Run method
Created a method to create a toast notification
private void SendNotification(string text)
{
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01);
XmlNodeList elements = toastXml.GetElementsByTagName("text");
foreach (IXmlNode node in elements)
{
node.InnerText = text;
}
ToastNotification notification = new ToastNotification(toastXml);
ToastNotificationManager.CreateToastNotifier().Show(notification);
}
Added code to the Run method
BackgroundTaskDeferral _deferral = taskInstance.GetDeferral();
RawNotification notification = (RawNotification)taskInstance.TriggerDetails;
string content = notification.Content;
// ...
SendNotification("test");
// ...
_deferral.Complete();
Updated my App's manifest to Toast Capable = YES and Lock Screen Notifications = Badge
Added a Declaration for a Background Task with Supported Task Type = Push Notification and Entry Point = NotificationServer.RawTask
Added code to register the Background Task
public static BackgroundTaskRegistration RegisterBackgroundTask(string taskEntryPoint,
string taskName,
IBackgroundTrigger trigger,
IBackgroundCondition condition)
{
//
// Check for existing registrations of this background task.
//
foreach (var cur in BackgroundTaskRegistration.AllTasks)
{
if (cur.Value.Name == taskName)
{
//
// The task is already registered.
//
return (BackgroundTaskRegistration)(cur.Value);
}
}
//
// Register the background task.
//
var builder = new BackgroundTaskBuilder();
builder.Name = taskName;
builder.TaskEntryPoint = taskEntryPoint;
builder.SetTrigger(trigger);
if (condition != null)
{
builder.AddCondition(condition);
}
BackgroundTaskRegistration task = builder.Register();
return task;
}
And executing it with
var reg = RegisterBackgroundTask("NotificationServer.RawTask", "RawNotifications", new PushNotificationTrigger(), null);
Is there something I'm missing here, my app doesn't seem to be responding to the Push Notification event. I have made sure my app is associated with the app in the store and the pushes are being sent with the correct client secret and app ID.
There are four types of push notifications:
Tile update
Badge update
Toast notification
Raw notification
All Windows Runtime apps can use the first three push notifications when in the foreground. Only lock screen apps can receive raw push notifications from WNS.
so, you must make your app a lock screen app.
You can follow this topic to do that.
I have been building a WinForms desktop application using C# that interfaces with Asterisk using Aster.NET (formerly/forked from Asterisk.NET). We're having real trouble reliably identifying and tracking calls that are related to an individual extension/user.
The problem we're having is due to the unpredictable/fuzzy nature of the events fired/triggered by Asterisk, with them being massively variable depending on how the call is routed before it hits an extension.
For example, the event sequence/format is different when: a call hits an IVR before getting blind transferred; if a call hits an IVR before it is attended transferred; if a call goes direct to the user's extension.
This is further hampered by the way that Asterisk tracks each side of the call using a different Unique ID (e.g. the incoming side of the call has a different UID than the received side of the call). Whilst we've managed to account for that in the (subsequently ugly!) code, we're still hitting issues with accounting for the different routing paths the call can take.
As such, I'm looking for any advice on how we can do the following:
Reliably identify an incoming call to a user's extension
We need to be able to identify the extension being called and the originating caller ID (after either a blind or attended transfer and direct call from external)
Reliably track the Unique ID for that incoming call as it's used to link to the call recording
Reliably identify an outgoing call from a user's extension
With the same caveats as above in mind
As it stands at the minute we have an extremely complex chain of event handlers that operate differently dependent on the 'current state' of the app.
To give one example: if we detect a NewStateEvent with a ChannelState of 6 ('Up'), we check if there is an ongoing call in process and that the UIDs match, and if so then the current call has been answered. If the UIDs don't match, but other factors do (e.g. channel, connectedlinenum, etc), then we pick this up as being the 'other side' of the call (i.e. the receiving or incoming side).
I'm not sure if the problem lies with the API or with AMI - but whichever it is it's causing us some real headaches.
Any advice greatly appreciated.
Is it possible for you to update to Asterisk 12? The channel names in AMI are now stable in Asterisk 12.
https://wiki.asterisk.org/wiki/display/AST/AMI+v2+Specification
i'm using package Aster.NET in c# . firstly install latest package of aster.net
than check that code .this code work perfect for me .
manager = new ManagerConnection(address, port, user, password);
manager.UnhandledEvent += new ManagerEventHandler(manager_Events);
manager.NewState += new NewStateEventHandler(Monitoring_NewState);
try
{
// Uncomment next 2 line comments to Disable timeout (debug mode)
// manager.DefaultResponseTimeout = 0;
// manager.DefaultEventTimeout = 0;
manager.Login();
if (manager.IsConnected())
{
Console.WriteLine("user name : " + manager.Username);
Console.ReadLine();
}
}
catch (Exception ex)
{
Console.WriteLine("Error connect\n" + ex.Message);
manager.Logoff();
Console.ReadLine();
}
void manager_Events(object sender, ManagerEvent e)
{
Console.WriteLine("Event : " + e.GetType().Name);
}
void Monitoring_NewState(object sender, NewStateEvent e)
{
string state = e.State;
string callerID = e.CallerId;
Console.WriteLine("caller num ...", e.CallerIdNum);
//Console.WriteLine("state =", state);
//Console.WriteLine("callerID =", callerID);
if ((state == "Ringing") | (e.ChannelState == "5"))
{
Console.WriteLine("hello rining your phone now ...");
String connectedLineNum;
String connectedLineName;
Dictionary<String, String> attributes = e.Attributes;
attributes.TryGetValue("connectedlinenum", out connectedLineNum);
attributes.TryGetValue("connectedlinename", out connectedLineName);
// "callerID" - called phone number
// "connectedLineNum" - calling phone number
// CallIn. Incoming call
}
else if ((state == "Ring") | (e.ChannelState == "4"))
{
Console.WriteLine("hello out going your call ...");
// CallOut. Outcoming call
}
else if ((state == "Up") | (e.ChannelState == "6"))
{
String connectedLineNum;
String connectedLineName;
Dictionary<String, String> attributes = e.Attributes;
attributes.TryGetValue("connectedlinenum", out connectedLineNum);
attributes.TryGetValue("connectedlinename", out connectedLineName);
// "callerID" - called phone number
// "connectedLineNum" - calling phone number
// human lifted up the phone right no
Console.WriteLine("human lifted up the phone...");
}
}
If you want to know how to use 32feet.NET library to communicate with bluetooth devices, read the solution
I am currently trying to communicate via bluetooth between a computer and a self-built .NET Gadgeteer prototype.
The Gadgeteer prototype consists of the mainboard, a power supply and a bluetooth module. The module is in discoverable mode.
On the computer a custom bluetooth program based on 32feet .NET Bluetooth is running. The program detects all bluetooth devices in range and tries to pair with them. However, this is not done automatically at the moment, I have to enter a pairing code for the device.
How can I pair devices without entering the pairing code?
Devices are found, the problem is the pairing part. I experimented a lot, but didn't find a solution...
foreach (BluetoothDeviceInfo device in this.deviceList)
{
try
{
//BluetoothClient client = new BluetoothClient(this.CreateNewEndpoint(localAddress));
//BluetoothEndPoint ep = this.CreateNewEndpoint(device.DeviceAddress);
EventHandler<BluetoothWin32AuthenticationEventArgs> handler = new EventHandler<BluetoothWin32AuthenticationEventArgs>(HandleRequests);
BluetoothWin32Authentication auth = new BluetoothWin32Authentication(handler);
BluetoothSecurity.PairRequest(device.DeviceAddress, null);
}
}
This code block initiates the pairing and it works, but Windows is asking me to enter the pairing code for the device. I read about the BluetoothWin32Authentication to prevent this case but I don't get it right.
private void HandleRequests(object that, BluetoothWin32AuthenticationEventArgs e)
{
e.Confirm = true;
}
This is the code of the event handler (http://32feet.codeplex.com/wikipage?title=BluetoothWin32Authentication)
If you simply want to allow the pairing to go ahead when to SSP devices are connecting then handling the callback and setting e.Confirm=True will be enough -- but that is a little insecure...
I am confused -.- The goal is that the application and the gadgeteer module can send data in both directions without any user interference.
Is it true that I can't pair devices automatically without user interaction?
Is it true that if two device were already paired they can exchange data without user interaction?
I figured out how to solve my problems and my knowledge about Bluetooth connections is a bit bigger now. If someone else has problems with that, I provide my solution. The code examples represent the C# implementation of a bluetooth controller with the 32feet Bluetooth library.
Scanning
This means that devices in range are detected. My code:
// mac is mac address of local bluetooth device
BluetoothEndPoint localEndpoint = new BluetoothEndPoint(mac, BluetoothService.SerialPort);
// client is used to manage connections
BluetoothClient localClient = new BluetoothClient(localEndpoint);
// component is used to manage device discovery
BluetoothComponent localComponent = new BluetoothComponent(localClient);
// async methods, can be done synchronously too
localComponent.DiscoverDevicesAsync(255, true, true, true, true, null);
localComponent.DiscoverDevicesProgress += new EventHandler<DiscoverDevicesEventArgs>(component_DiscoverDevicesProgress);
localComponent.DiscoverDevicesComplete += new EventHandler<DiscoverDevicesEventArgs>(component_DiscoverDevicesComplete);
private void component_DiscoverDevicesProgress(object sender, DiscoverDevicesEventArgs e)
{
// log and save all found devices
for (int i = 0; i < e.Devices.Length; i++)
{
if (e.Devices[i].Remembered)
{
Print(e.Devices[i].DeviceName + " (" + e.Devices[i].DeviceAddress + "): Device is known");
}
else
{
Print(e.Devices[i].DeviceName + " (" + e.Devices[i].DeviceAddress + "): Device is unknown");
}
this.deviceList.Add(e.Devices[i]);
}
}
private void component_DiscoverDevicesComplete(object sender, DiscoverDevicesEventArgs e)
{
// log some stuff
}
Pairing
This means that devices get coupled with the local bluetooth device. This needs to be done once by entering a code of both sides. Can be done via code so that the user doesn't even notice that a device was added. My code for this purpose:
// get a list of all paired devices
BluetoothDeviceInfo[] paired = localClient.DiscoverDevices(255, false, true, false, false);
// check every discovered device if it is already paired
foreach (BluetoothDeviceInfo device in this.deviceList)
{
bool isPaired = false;
for (int i = 0; i < paired.Length; i++)
{
if (device.Equals(paired[i]))
{
isPaired = true;
break;
}
}
// if the device is not paired, pair it!
if (!isPaired)
{
// replace DEVICE_PIN here, synchronous method, but fast
isPaired = BluetoothSecurity.PairRequest(device.DeviceAddress, DEVICE_PIN);
if (isPaired)
{
// now it is paired
}
else
{
// pairing failed
}
}
}
Connecting
This means establishing a connection and exchanging of data. Again some code:
// check if device is paired
if (device.Authenticated)
{
// set pin of device to connect with
localClient.SetPin(DEVICE_PIN);
// async connection method
localClient.BeginConnect(device.DeviceAddress, BluetoothService.SerialPort, new AsyncCallback(Connect), device);
}
// callback
private void Connect(IAsyncResult result)
{
if (result.IsCompleted)
{
// client is connected now :)
}
}
If you keep the order scan, pair, connect, everything should work fine. To send or receive data, use the GetStream() method of the BluetoothClient. It provides a network stream that can be manipulated.
Receiving a connection
If you want another device to connect with your device you need to listen to incoming connection requests. This only works if the device have already been paired before. My code:
BluetoothListener l = new BluetoothListener(LOCAL_MAC, BluetoothService.SerialPort);
l.Start(10);
l.BeginAcceptBluetoothClient(new AsyncCallback(AcceptConnection), l);
void AcceptConnection(IAsyncResult result){
if (result.IsCompleted){
BluetoothClient remoteDevice = ((BluetoothListener)result.AsyncState).EndAcceptBluetoothClient(result);
}
}
Replace LOCAL_MAC with a valid BluetoothAddress (e.g. by using BluetoothAddress.Parse();). After the devices are connected they can exchange messages via the underlying stream. If the connection does not work there might be authentication issues, so try setting the local device pin in the listener (l.SetPin(LOCAL_MAC, MY_PASSWORD);
I have an app which can(possibly) show two toast notifications to the user one after the other. I observed that if such scenario arises then only one of the two notifications is displayed to the user but once the user launches the app and then same notifications are presented to the user in message boxes and if he clicks "cancel" for the first message and then the next notification is presented. So, my doubt now is, If two toast notifications are there then how will the device handle it? and which of the two is displayed to the user? And in case only notification is presented to the user (by default behaviour of the device) then is there a way to display notifications one after the other?
This is similar to this QUESTION but i want to know the behaviour of WP7 phones as the features of WP7 very different other smartphone OSes.
All suggestions, comments and answers are appreciated.
Thank You
Windows Phone 7 has the potential to show both the messages, and which one first depends on which one the phone receives first.
If you look at the diagram on this page http://msdn.microsoft.com/en-us/library/windowsphone/develop/ff402558(v=vs.92).aspx you see that there is a lot of communication in sending a push (toast, tile or raw) notification. And it depends on the Microsoft Push Notification Service which normally sends it first come first serve.
So from the sounds of it, I would look into trying to limit how your application sends the toast notifications. So check if a toast notification has been sent to the phone within a certain amount of time, if so hold of on sending the next one in till that time has past.
Also remember to check if the MPNS actually sent the push notification to the, that will help in determining if the phone might have received the notification
In that link I post it goes into a lot of details about sending and receiving the push notifications.
What I did is this,
public static void ShowToast()
{
try
{
string langKey = CacheManager.getInstance().getDataFromConfigFile(CacheManager.APP_CURRENT_LANGUAGE);
string flag = CacheManager.getInstance().getDataFromConfigFile(CacheManager.APP_UPGRADE_STATUS);
string catalogUpdateFlag = CacheManager.getInstance().getDataFromConfigFile(CacheManager.APP_CATALOG_UPGRADE_STATUS);
CultureInfo ci;
if ((null == langKey) || (langKey.Equals(Utils.LANGUAGE_EN)))
{
ci = new CultureInfo("en-US");
}
else
{
ci = new CultureInfo("fr-FR");
}
AppResources.Culture = ci;
if (!Utils.isNullString(flag))
{
var toast = new ShellToast
{
Title = AppResources.APP_NAME,
Content = getMessageStatus(flag),
NavigationUri = new System.Uri("/MainPage.xaml", System.UriKind.Relative)
};
Logger.log(TAG, ":ShowToast():MessageToUser" + AppResources.APP_NAME + getMessageStatus(flag));
toast.Show();
}
if (!Utils.isNullString(catalogUpdateFlag))
{
var toast = new ShellToast
{
Title = AppResources.APP_NAME,
Content = getMessageStatus(catalogUpdateFlag),
NavigationUri = new System.Uri("/MainPage.xaml", System.UriKind.Relative)
};
Logger.log(TAG, ":ShowToast():MessageToUser" + AppResources.APP_NAME + getMessageStatus(catalogUpdateFlag));
toast.Show();
}
}
catch (Exception ex)
{
Logger.log(TAG, "Exception in ShowToast: " + ex.Message + "\n" + ex.StackTrace);
}
}
private static string getMessageStatus(string flagType)
{
//string flag = CacheManager.getInstance().getApplicationSettings(CacheManager.APP_UPGRADE_STATUS);
string flag = CacheManager.getInstance().getDataFromConfigFile(CacheManager.APP_UPGRADE_STATUS);
string catalogUpdateFlag = CacheManager.getInstance().getDataFromConfigFile(CacheManager.APP_CATALOG_UPGRADE_STATUS);
if (flagType == flag)
{
if (flag.Equals(CacheManager.MAJOR_UPGRADE))
{
return AppResources.APP_UPGRADE_CONFIRM;
}
else if (flag.Equals(CacheManager.MINOR_UPGRADE))
{
return AppResources.APP_UPGRADE_MINOR_CONFIRM;
}
}
else if (flagType == catalogUpdateFlag)
{
return AppResources.APP_CATALOG_CONFIRM;
}
return "";
}
I have taken two different variables to know if its the application upgrade or just the catalogue upgrade(New items will be added to the existing ones). So if there is catalogue upgrade and/or application upgrade user will be notified.