I have already successfully used BLE advertising to broadcast information from one android device and receive it on another. Now I want the observer to be a Unity-app running on the HoloLens v2. The HoloLens does not need to connect to the android-device as I am aware that this does not seem to be supported. I am looking for a broadcaster -> observer solution.
As mentioned, I already have the broadcaster written and it works fine with android -> android. Now I have implemented my observer in Unity, largely inspired by this article, and it looks like this:
#if ENABLE_WINMD_SUPPORT
using System;
using Windows.Devices.Bluetooth.Advertisement;
#endif
public class DemoManager : MonoBehaviour
{
[SerializeField] private StatusDisplay statusDisplay;
private void Awake()
{
#if ENABLE_WINMD_SUPPORT
StartWatcher();
#else
statusDisplay.Display("UWP APIs are not supported on this platform!");
#endif
}
#if ENABLE_WINMD_SUPPORT
private void StartWatcher()
{
void OnAdvertisementReceived(object sender, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
statusDisplay.Display("Advertisement received!");
}
try {
BluetoothLEAdvertisementWatcher watcher = new BluetoothLEAdvertisementWatcher();
watcher.AdvertisementFilter.Advertisement.ManufacturerData.Add(GetManufacturerData());
watcher.Received += OnAdvertisementReceived;
watcher.Start();
statusDisplay.Display("Watcher started!");
} catch (Exception e){
statusDisplay.Display($"Watcher could not start! Error: {e.Message}");
}
}
private BluetoothLEManufacturerData GetManufacturerData()
{
var manufacturerData = new BluetoothLEManufacturerData();
manufacturerData.CompanyId = 1234;
return manufacturerData;
}
#endif
}
The StatusDisplay script is used for displaying text in a thread-safe way. The company-id 1234 is also used by the broadcaster.
My app has bluetooth capabilities (enabled both in the Unity-editor and in the built solution)
All looks very promising, but sadly the advertisement never seems to be received, or at the very least I am getting no corresponding status message.
Does anybody have any ide what might be wrong? Does anyone have any experience with this problem?
We tested the Bluetooth.Advertisement API and works well on the HoloLens. I found that you assigned the CompanyId(a 16-bit unsigned integer) property a signed decimal number, but we usually provide a hexadecimal number as a Bluetooth LE company identifier code. Could you double-check this point both in your watcher and publisher? For example, it should look like 0xFFFE. Besides, more information about how to use the Bluetooth Advertisement API to send and receive Bluetooth Low Energy advertisements please see:Bluetooth advertisement sample
The problem was not with the Unity-side. My advertisement was malformed. I tested my advertisements with a observer that I also wrote myself on Android. So I accounted for the incorrect formatting there, but of course, the C# Advertisement-watcher did not.
Related
I would like to be informed, if a (Android) USB device of a specific interface (USB debugging) is connected to my Windows computer.
For this, I'm trying to use .Net with this code:
const string GUID_DEVINTERFACE_ANDROID = "f72fe0d4-cbcb-407d-8814-9ed673d0dd6b";
const string usbDeviceSelector = "System.Devices.InterfaceClassGuid:=\"{" + GUID_DEVINTERFACE_ANDROID + "}\" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True";
_usbDeviceWatcher = DeviceInformation.CreateWatcher(
usbDeviceSelector,
new string[] { "System.Devices.InterfaceEnabled" },
DeviceInformationKind.AssociationEndpoint);
_usbDeviceWatcher.Updated += UsbDeviceWatcher_Updated;
Unfortunately, the event will not be thrown to my UsbDeviceWatcher_Update function.
I don't want to be informed about a specific device, I want to be notified about all devices, which supports this interface.
How can I get an event, if an device with this special interface will be connected / disconnected from my computer?
If there is a WinUsb solution for this, I would be happy too.
Filter for the a USB device with the interface class {f72fe0d4-cbcb-407d-8814-9ed673d0dd6b} and then subscribe to the Added and Removed events:
using Windows.Devices.Enumeration;
using Windows.Devices.Usb;
var filter = UsbDevice.GetDeviceSelector(new Guid("f72fe0d4-cbcb-407d-8814-9ed673d0dd6b"));
var usbDeviceWatcher = DeviceInformation.CreateWatcher(filter);
usbDeviceWatcher.Added += UsbDeviceWatcher_Added;
usbDeviceWatcher.Removed += UsbDeviceWatcher_Removed;
usbDeviceWatcher.Start();
Console.WriteLine("Press key to exit...");
Console.ReadKey();
void UsbDeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
{
Console.WriteLine("Added");
}
void UsbDeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
{
Console.WriteLine("Removed");
}
Alternatively, you can also filter for interface class 0xff, subclass 0x42 and protocol 0x01:
var filter = UsbDevice.GetDeviceClassSelector(new UsbDeviceClass() {
ClassCode = 0xff,
SubclassCode = 0x42,
ProtocolCode = 0x01
});
You can also implement the approach proposed by David Grayson's. But it's considerably more effort.
The standard way to get notified of new or removed USB devices in Windows is to listen for the WM_DEVICECHANGE message sent by the OS to your window. This will give you more notifications than you care about, so whenever you get that message, you should use your favorite library or program to list the devices you care about and see if anything changed.
You will need to override your windows WndProc message. The documentation here discusses how to do that in C#:
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.wndproc?view=windowsdesktop-7.0
With this setup, I've been able to get two android phones to send and receive UDP broadcasts. I can also use this setup to send a UDP broadcast from a physical Android device to an iPhone.
However, my problem is that it doesn't seem to work the other way around. The send function is ran on the iPhone, and the receive function is being run on the Android phone. The Android phone never gets the broadcast. It seems like something is wrong with the iPhone's sending function. Here's the setup:
The Android side that has worked for me before:
const port = 37069;
const address = '224.0.0.1';
void receive() async {
final socket = await RawDatagramSocket.bind(address, port);
socket.multicastHops = 1;
socket.broadcastEnabled = true;
socket.writeEventsEnabled = true;
socket.listen((RawSocketEvent event) {
print("still listening...");
final packet = socket.receive();
print("The packet was $packet");
print("It came from ${packet?.address}");
});
}
and this is the iPhone side, that seems to be the problem. I'm not getting errors, so I'm wondering if there are any permissions in the Info.plist file that need to be added?
void broadcast() {
// for the iphone
RawDatagramSocket.bind(address, port).then((RawDatagramSocket socket) {
socket.multicastLoopback = false;
socket.broadcastEnabled = true;
socket.readEventsEnabled = true;
for (int i = 0; i < 150; i++) {
socket.send("Sent #$i".codeUnits, InternetAddress(address), port);
print("sent $i");
}
socket.close();
});
}
I've tested this same setup in my project, and it has worked in the following situations:
Android -> Android
Android -> iOS
but, iOS -> Android doesn't work. When I run the app, I can see that the iPhone is indeed sending the data, but the Android isn't receiving anything. Is the Android side the problem? What am I doing wrong?
I ended up using a package called Bonsoir to achieve what I wanted to.
It lets you broadcast and receive network services, and I'm pretty sure its the same underlying technology as household programs like Airplay and Google Casting. It's also very reliable and simple to use.
To send a certain string, I passed in a string argument in the form of a dictionary into the attributes attribute within the BonsoirService class.
The package can be found here.
Making an app right now that interacts with an ESP32 through bluetooth classic. I'm reading the hall sensor and sending a 0 when its value is above 0, and a 1 when below. Now, when I register that 1 in ai2 and some things happen in the app because of it, the ESP32 malfunctions or something. I stop getting readings from the sensor in the serial monitor, and the bluetooth connection stops. It just seems like the whole esp just stops dead in its tracks. I'm also not sending any data to the ESP32, just receiving from it. The esp code is super small, but the app code not so much.
Only way to fix this issue is resetting the esp, which isn't really doable in my usecase. Any way to fix this?
#include "BluetoothSerial.h"
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif
BluetoothSerial SerialBT;
void setup() {
Serial.begin(115200);
SerialBT.begin("Sport Spel"); //Bluetooth device name
}
void loop() {
Serial.println(hallRead());
if (SerialBT.available)
{
if (hallRead() < 0)
{
SerialBT.write('1');
}
else
{
SerialBT.write('0');
}
delay(20);
}
}
Image 1 of app code
Image 2
3
4
5
6
The line
if (SerialBT.available)
should be
if (SerialBT.available())
As it's written in your question, you're testing whether the address of the method named available on the SerialBT object is true, which it always will be. You want to actually call that method, so you need to include the parentheses in order to invoke it.
I am writing an app which will be run in tablets. The tablet will be connected to ACR1222L NFC reader.
I am using their android library to interact with the reader. I can detect the USB reader and also can read the readers name.
BUT i am struggling to read data from NFC tag. In fact I have no clue where to start, which classes/methods to use.
Is there anyone who already worked with ACR1222L and its android library?
Some guidelines, sample code, tutorial would save my life.
EDIT:
Well, I got little smarter now, I can read the UID. this is how to do it.
#Override
protected void onCreate(Bundle savedInstanceState) {
............... your code
mReader = new Reader(mManager);
mReader.setOnStateChangeListener(new OnStateChangeListener() {
#Override
public void onStateChange(int slotNum, int prevState, int currState) {
//This command is for the card UID
byte[] command = {(byte) 0xFF,(byte) 0xCA,0x00,0x00,0x00};
byte[] response = new byte[300];
int responseLength;
if (currState == Reader.CARD_PRESENT) {
try {
mReader.power(slotNum,Reader.CARD_WARM_RESET);
mReader.setProtocol(slotNum, Reader.PROTOCOL_T0| Reader.PROTOCOL_T1);
responseLength=mReader.transmit(slotNum,command, command.length, response,response.length);
//Here i have the card UID if i send the proper command
responsedata=NfcUtils.convertBinToASCII(response);
}
}
}
BUT I am still struggling to read the payload from the tag. I have also look into nfctools library. But I don't know where to start. Would be great if anyone guide my through the library.
Yes, this is possible - and quite the same as working with the ACR 122 as the API is almost identical.
I've developed a (commmercially available) library which probably does most of what you're looking into, or can serve as a starting point for your own implementation.
I need to know UUID on API 8 (2.2) or possibly 2.3.3.
As I understand the documentation, this should be allowed:
phoneDevice = blueAdapter.getRemoteDevice(phoneAddress);
ParcelUuid[] phoneUuids = phoneDevice.getUuids(); // Won't compile
Eclipse gives me:
"The method getUuids() is undefined for the type BluetoothDevice."
But see:
http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#getUuids()
Also, I would like to know how the UUIDs are "parceled" inside the ParcelUuid[]. In case I ever manage to get there, how do I retrieve a UUID from a parcelUuid[]? Documentation for Android bluetooth seems to be very poor, in my opinion.
What a joke!
Now I try to get it from the intent, but this too gives: *"EXTRA_UUID cannot be resolved or is not a field"*:
intent.getParcelableExtra(BluetoothDevice.EXTRA_UUID);
You have to use reflection to use the getUuids() and fetchUuidsWithSdp() on android version < 3. So, try the code:
Method method = phoneDevice.getClass().getMethod("getUuids", null);
ParcelUuid[] phoneUuids = (ParcelUuid[]) method.invoke(phoneDevice, null);
//this will support from API level 15 and above.
Broadcast Action: This intent is used to broadcast the UUID wrapped as a ParcelUuid of the remote device after it has been fetched. This intent is sent only when the UUIDs of the remote device are requested to be fetched using Service Discovery Protocol
Always contains the extra field EXTRA_DEVICE
Always contains the extra field EXTRA_UUID
Requires BLUETOOTH to receive.
Constant Value: "android.bluetooth.device.action.UUID"
//no way to degrade its hardware related. there is no supporting jar also. http://developer.android.com/sdk/compatibility-library.html
Unfortunately, I don't think there is any good way to get the UUID's supported by a BluetoothDevice with API level < 15. I guess that's why they added the new functions in API 15.
Note, from the docs for BluetoothClass
BluetoothClass is useful as a hint to roughly describe a device (for
example to show an icon in the UI), but does not reliably describe
which Bluetooth profiles or services are actually supported by a
device. Accurate service discovery is done through SDP requests, which
are automatically performed when creating an RFCOMM socket with
createRfcommSocketToServiceRecord(UUID) and
listenUsingRfcommWithServiceRecord(String, UUID).
So, perhaps the device class could be used as a hint as to what services will be available until you perform one of the listed functions. Certainly it doesn't hurt to check the class since this won't require any additional bluetooth operations.
Note that the service class is also available (it is part of the device class) but this is just a general class, not a listing of specific services (like from SDP).
try BluetoothAdapter class
any question, read: http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html
In case you can not get UUID from getUuids() method. Please try the other way.
After scanned successfully, you should receive byte[] (scanRecord), so from this result, if you can recognize UUID format you can split step by step to get correct UUID as these codes.
P/s : Important thing, you should know UUID format to get from index correctly.
// Put item into hash map
// UUID from index 10 to 24 : 12233445566778899aabbccddeeff0
StringBuilder mSbUUID = new StringBuilder();
for (int i = 0; i < scanRecord.length; i++) {
// UUID
if (i >= 10 & i <= 24) {
if (Integer.toHexString(
scanRecord[i]).contains("ffffff")) {
mSbUUID.append(Integer.toHexString(scanRecord[i]).replace("ffffff", "") + "-");
} else {
mSbUUID.append(Integer.toHexString(scanRecord[i]) + "-");
}
}
}