bluetooth gatt server : how to set the appearance characteristic? - bluetooth-lowenergy

I've created a Bluetooth Gatt server on Android : I was able to implement/configure a new service (thanks to the https://github.com/androidthings/sample-bluetooth-le-gattserver), but unfortunately, I am not able to change the "appearance" of the service.
From my understanding, I need to modify the Appearance characteric of the Generic Access Profile (https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile), but I'm stuck as it does not exit, and if try to create it, it fails with a status=133 error. (https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/android-5.1.1_r13/stack/include/gatt_api.h)
final UUID SERVICE_GENERIC_ACCESS = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb");
final UUID CHARACTERISTIC_APPEARANCE = UUID.fromString("00002a01-0000-1000-8000-00805f9b34fb");
BluetoothManager mBluetoothGattServer = mBluetoothManager.openGattServer(this, mGattServerCallback);
BluetoothGattService genericService = mBluetoothGattServer.getService(SERVICE_GENERIC_ACCESS);
BluetoothGattService genericService = new BluetoothGattService(
SERVICE_GENERIC_ACCESS,
BluetoothGattService.SERVICE_TYPE_PRIMARY);
BluetoothGattCharacteristic icon = new BluetoothGattCharacteristic(CHARACTERISTIC_APPEARANCE, BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ);
mBluetoothGattServer.addService(genericService);
public void onServiceAdded(int status, BluetoothGattService service) {
// Fails with error 133
}
Any help will be appreciated!
Cheers
D

Related

How to capture custom parameters in firebase deep link in Unity?

everyone!
I'm working for the first time ever in a Unity game project using Firebase.
We configure our deep link in Firebase console to open our game in a specific mode when te deep link was sent.
That part works well. But we have a big issue:
We need to get a value form a custom parameter in the URL, because our server generates a random username for our game to make a Leader Board sandbox everytime the deep link was sent.
So we configure our deep link in Firebase console like this:
https://exemple.page.link/gamemode?username=123
But, in this case, the username will always be 123. However, the server will always send the link with a random user, for example:
https://exemple.page.link/gamemode?username=8b9d-1c6b-c52a3-b0d7
If we leave the username parameter blank, even if the server sent the random username, we receive nothing in our link in Unity, just:
https://exemple.page.link/gamemode?username
If I manage to get the link in a browser in my Android device, I get the random username properly. But when the game opens, this value was lost!
To receive the dynamic link, we just use the void OnDynamicLink(object sender, EventArgs args) in our Firebase Manager script in Unity.
So, my question is:
There is a way to receive the username parameter with a dynamic value? If the answer is 'yes', there's a method to get that custom value? Or I just missed up something in the firebase configuration or even the deep link in Firebase console?
Thanks in advance!
From Receive Dynamic Links with Unity you need to cast to ReceivedDynamicLinkEventArgs
void OnDynamicLink(object sender, EventArgs args)
{
var dynamicLinkEventArgs = args as ReceivedDynamicLinkEventArgs;
Debug.Log($"Received dynamic link {dynamicLinkEventArgs.ReceivedDynamicLink.Url.OriginalString}");
}
and then if there is only this one parameter anyway you could probably simply do e.g.
var query = dynamicLinkEventArgs.ReceivedDynamicLink.Url.Query;
var username = query.Split('=')[1];
or if there can be more parameter
var query = dynamicLinkEventArgs.ReceivedDynamicLink.Url.Query;
// first Split into the individual patamters
var patamters = query.Split('&');
string username = null;
foreach(var parameter in parameters)
{
// Then split into key and value
var keyValue = parameter.Split('=');
if(keyValue[0] == "username")
{
username = keyValue[1];
break;
}
}
or if you happen to be a fan of Linq (not sure if this is the most elegant though)
var query = dynamicLinkEventArgs.ReceivedDynamicLink.Url.Query;
var username = query.Split('&').Select(parameter => parameter.Split('=').Where(keyValue => keyValue[0] == "username").Select(keyValue => keyValue[1]).FirstOrDefault();

How to correlate two AppInsights resources that communicate through NServiceBus?

Currently, I have dozens of .NET services hosted on various machines that show up as Resources on my AppInsights Application Map, which also shows their dependencies with respect to each other, based on the HTTP requests they make.
However, the relationships between services that communicate through NServiceBus (RabbitMQ) are not shown. Now, I am able to show the messages that are either sent or handled by a service via calls to TelemetryClient.TrackXXX(), but not connect Resources on the map using this information.
I have even gone so far as to attach the parent operation ID from the NSB message sender to the message itself, and assign it to the telemetry object in the receiver, but there is still no line drawn between the services in the Application Map.
To reiterate, this is what I'm getting in the Application Map:
(NSB Message Sender) --> (Message sent/handled)
And this is what I want:
(NSB Sender) --> (Receiver)
The services in question are .NET Core 3.1.
I cannot provide the code, as this is for my work, but any help would be greatly appreciated. I've searched everywhere, and even sources that seemed like they would help, didn't.
(not signed in, posting from work)
Alright, I finally got it. My approach to correlate AppInsights resources using their NSB communication is to mimic HTTP telemetry correlation.
Below is an extension method I wrote for AppInsights' TelemetryClient. I made a subclass named RbmqMessage:NServiceBus.IMessage, given my applications use RBMQ, and gave it the following properties for the sake of correlation (all set in the service that sends the message) :
parentId: equal to DependencyTelemetry.Id
opId: value is the same in the sender's DependencyTelemetry and the receiver's RequestTelemetry. Equal to telemetry.context.operation.id
startTime: DateTime.Now was good enough for my purposes
The code in the service that sends the NSB message:
public static RbmqMessage TrackRbmq(this TelemetryClient client, RbmqMessage message)
{
var msg = message;
// I ran into some issues with Reflection
var classNameIdx = message.ToString().LastIndexOf('.') + 1;
var messageClassName = message.ToString().Substring(classNameIdx);
var telemetry = new DependencyTelemetry
{
Type = "RabbitMQ",
Data = "SEND "+messageClassName,
Name = "SEND "+messageClassName,
Timestamp = DateTime.Now,
Target = "RECEIVE "+messageClassName //matches name in the service receiving this message
};
client.TrackDependency(telemetry);
msg.parentId = telemetry.Id;
msg.opId = telemetry.Context.Operation.Id; //this wont have a value until TrackDependency is called
msg.startTime = telemetry.Timestamp;
return msg;
}
The code where you send the NSB message:
var msg = new MyMessage(); //make your existing messages inherit RbmqMessage
var correlatedMessage = _telemetryClient.TrackRbmq(msg);
MessageSession.Publish(correlatedMessage); //or however the NSB message goes out in your application
The extension method in the NServiceBus message-receiving service:
public static void TrackRbmq(this TelemetryClient client, RbmqMessage message)
{
var classnameIdx = message.ToString().LastIndexOf('.')+1;
var telemetry = new RequestTelemetry
{
Timestamp = DateTime.Now,
Name = "RECEIVE "+message.ToString().Substring(classNameIdx)
};
telemetry.Context.Operation.ParentId = message.parentId;
telemetry.Context.Operation.Id = message.opId;
telemetry.Duration = message.startTime - telemetry.Timestamp;
client.TrackRequest(telemetry);
}
And finally, just track and send the message:
var msg = new MyMessage();
_telemetryClient.TrackRbmq(msg);
MessagePipeline.Send(msg); //or however its sent in your app
I hope this saves someone the trouble I went through.

Bluetooth LE device - how to recognize a certain type of device in mobile app?

I am learning to program with Bluetooth LE Devices and writing a simple mobile app. Here is my entry-level question:
Say I only want to connect to a certain type of Bluetooth LE device (like a blood pressure device), but when I do a scan it could return more than one result if there are other Bluetooth LE device present in range. So I might get the following results:
Device 1 RSSI, Device 1 Name, Device 1 Address;
Device 2 RSSI, Device 2 Name, Device 2 Address
...
How can I tell the code to pick up the type of device that I want (in this case, the blood pressure device)? Does the device address get assigned by the vendor of the product and are they unique enough and following a scheme that I can use to identify this type of device? If not, what other option do I have for the app to automatically recognize a certain type of Bluetooth device?
If you want to pick up the particular device means you have to mention in displayGattServices.
For Example :-for using heart rate sensor device you have mentioned like this
if (SampleGattAttributes.lookup(uuid, unknownCharaString)
.contains("Heart")) {
hrt_rate_char = gattCharacteristic;
}
For Detail see displayGattServices method:
private void displayGattServices(List<BluetoothGattService> gattServices) {
if (gattServices == null)
return;
String uuid = null;
String unknownServiceString = getResources().getString(
R.string.unknown_service);
String unknownCharaString = getResources().getString(
R.string.unknown_characteristic);
ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<HashMap<String, String>>();
ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData = new ArrayList<ArrayList<HashMap<String, String>>>();
mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
for (BluetoothGattService gattService : gattServices) {
HashMap<String, String> currentServiceData = new HashMap<String, String>();
uuid = gattService.getUuid().toString();
currentServiceData.put(LIST_NAME,
SampleGattAttributes.lookup(uuid, unknownServiceString));
currentServiceData.put(LIST_UUID, uuid);
gattServiceData.add(currentServiceData);
ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList<HashMap<String, String>>();
List<BluetoothGattCharacteristic> gattCharacteristics = gattService
.getCharacteristics();
ArrayList<BluetoothGattCharacteristic> charas = new ArrayList<BluetoothGattCharacteristic>();
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
charas.add(gattCharacteristic);
HashMap<String, String> currentCharaData = new HashMap<String, String>();
uuid = gattCharacteristic.getUuid().toString();
if (SampleGattAttributes.lookup(uuid, unknownCharaString)
.contains("Heart")) {
hrt_rate_char = gattCharacteristic;
}
currentCharaData.put(LIST_NAME,
SampleGattAttributes.lookup(uuid, unknownCharaString));
currentCharaData.put(LIST_UUID, uuid);
gattCharacteristicGroupData.add(currentCharaData);
}
mGattCharacteristics.add(charas);
gattCharacteristicData.add(gattCharacteristicGroupData);
}
}
The above code won't work. You will have to scan the device, connect to it, and discover the services. A heart rate device has a specific service characteristic. Here is a link for that:
https://developer.bluetooth.org/TechnologyOverview/Pages/HRP.aspx
check out this link of an answer I have that demonstates heart rate device:
https://stackoverflow.com/a/29548205/862382
Suppose if you want your app to connect only to Hear Rate monitoring devices, and if you have the liberty to connect and check, you should use the standard Heart Rate service implementation. But, suppose if you want to get it done without connecting to a BLE device, Appearance field in the advertisement packet should help you, provided that BLE Server developers have taken proper care to set the device appearance in the GAP service.
Appearance values 832 and 833 are for Generic Heart rate Sensor and Heart Rate Sensor: Heart Rate Belt.
That said, be assured that you will also have the capability to connect to custom devices that implement Heart Rate Service as a supplementary service with their primary application, only if the custom service has the GAP characteristics Appearance set to 833 or 832.

DotRas unauthorized access exception when adding phonebook an entry

I am devoloping an application with dotras dll. In the application my main goal is to connect to the internet with 3g USB modem. I am adding my code below :
RasPhoneBook book = new RasPhoneBook();
book.Open();
dialer = new RasDialer();
dialer.StateChanged += new EventHandler<StateChangedEventArgs> (dialer_StateChanged);
RasDevice device = RasDevice.GetDeviceByName("ZTE", RasDeviceType.Modem);
RasEntry entry = RasEntry.CreateDialUpEntry("MyEntry", "*99#", device);
entry.EncryptionType = RasEncryptionType.Optional;
entry.Options.ModemLights = true;
entry.NetworkProtocols.IP = true;
entry.NetworkProtocols.Ipx = false;
book.Entries.Add(entry);
dialer.PhoneBookPath = book.Path;
dialer.EntryName = "MyEntry";
dialer.Dial();
When I tried to add the phonebook my entry it's returning an exception :
UnauthorizedAccessException was Unhandled
The caller does not have required permission to perform the action requested.
I'm new about DotRas. So which permissions does it neeeded to add an entry to the phonebook?
Any ideas?
I have found the answer. The reason why I need to elevate privileges for the application is due to the application opening the All User's profile phone book. This is indicated by my call to book.Open()
If you encountered a problem like this remember you can always store the phone book next to your application, which will remove the need to elevate permissions.
The code should be :
RasPhoneBook book = new RasPhoneBook();
book.Open(".\\MyAppPhoneBook.pbk");

What hinders NetStream.onPeerConnect from being triggered?

I'm using Adobe Stratus (now renamed to Cirrus) to build a p2p application. Inside the application, I used NetStream.onPeerConnect callback function and expected it to be triggered every time when a peer is connected. However, it always failed with my friend A while strangely friend B managed to have the function called without any problem.
I was wondering what could be the cause to this issue?
Here are how the code pieces look like.
First of all, create a NetConnection.
netConnection = new NetConnection();
netConnection.addEventListener(NetStatusEvent.NET_STATUS, netConnectionHandler);
netConnection.connect(SERVER_ADDRESS+DEVELOPER_KEY);
Secondly, create NetStream upon NetConnection successfully connected.
private function netConnectionHandler(event:NetStatusEvent):void{
switch (event.info.code){
case "NetConnection.Connect.Success":
sendStream = new NetStream(netConnection, NetStream.DIRECT_CONNECTIONS);
sendStream.addEventListener(NetStatusEvent.NET_STATUS, netStreamHandler);
var sendObj:Object = new Object();
sendObj.onPeerConnect = function(subscriber:NetStream) : Boolean {
trace("[onPeerConnect] far id: " + subscriber.farID);
return true;
}
sendStream.client = sendObj;
sendStream.publish("file");
......
Thirdly, here's how I build the connection between two peers
receivedStream = new NetStream(netConnection, farId);
receivedStream.client = this;
receivedStream.addEventListener(NetStatusEvent.NET_STATUS, incomingStreamHandler);
receivedStream.play("file");
Please help enlighten me. Thanks!
It turns out my friend A is behind a symmetric NAT. I'm thinking to setup a TURN server for us to build a successful connection.

Resources