I am new to using bluetoothctl and am looking for some advice.
So, I try the following:
$ bluetoothctl power on
Changing power on succeeded
$ bluetoothctl devices
Device B3:50:46:84:F1:CF M6
The M6 is the smartwatch.
$ bluetoothctl connect B3:50:46:84:F1:CF
Attempting to connect to B3:50:46:84:F1:CF
Connection successful
Great!
$ bluetoothctl
Agent registered
[M6 ]# info
Device B3:50:46:84:F1:CF (public)
Name: M6
Alias: M6
Appearance: 0x00c8
Paired: yes
Trusted: yes
Blocked: no
Connected: yes
WakeAllowed: yes
LegacyPairing: no
UUID: Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb)
UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
UUID: Device Information (0000180a-0000-1000-8000-00805f9b34fb)
UUID: Battery Service (0000180f-0000-1000-8000-00805f9b34fb)
UUID: Human Interface Device (00001812-0000-1000-8000-00805f9b34fb)
UUID: Unknown (0000fffa-0000-1000-8000-00805f9b34fb)
UUID: Unknown (0000ffff-0000-1000-8000-00805f9b34fb)
UUID: Vendor specific (6e400001-b5a3-f393-e0a9-e50e24dcca9d)
Modalias: usb:v1915pEEEEd0001
Battery Percentage: 0x36 (54)
[M6 ]# menu gatt
Menu gatt:
Available commands:
-------------------
list-attributes [dev/local] List attributes
select-attribute <attribute/UUID> Select attribute
attribute-info [attribute/UUID] Select attribute
read [offset] Read attribute value
write <data=xx xx ...> [offset] [type] Write attribute value
acquire-write Acquire Write file descriptor
release-write Release Write file descriptor
acquire-notify Acquire Notify file descriptor
release-notify Release Notify file descriptor
notify <on/off> Notify attribute value
clone [dev/attribute/UUID] Clone a device or attribute
register-application [UUID ...] Register profile to connect
unregister-application Unregister profile
register-service <UUID> [handle] Register application service.
unregister-service <UUID/object> Unregister application service
register-includes <UUID> [handle] Register as Included service in.
unregister-includes <Service-UUID><Inc-UUID> Unregister Included service.
register-characteristic <UUID> <Flags=read,write,notify...> [handle] Register application characteristic
unregister-characteristic <UUID/object> Unregister application characteristic
register-descriptor <UUID> <Flags=read,write...> [handle] Register application descriptor
unregister-descriptor <UUID/object> Unregister application descriptor
back Return to main menu
version Display version
quit Quit program
exit Quit program
help Display help about this program
export Print environment variables
Now, what i want to do is to set the date and time on this smartwatch. I am also interested in reading other information such as heart rate, temperature, etc. How do I do that?
Thanks!
Related
I am using a Fire TV Remote Control Version 1, the old one which has no volume and power buttons.
What I want to achieve is, receive audio samples from the build in mic of this remote.
I am using a Raspberry Pi 4 with debian
Linux raspi4box 5.4.79-v7l+ #1373 SMP Mon Nov 23 13:27:40 GMT 2020 armv7l GNU/Linux
I have paired the Remote with bluetoothctl successfully and can read the key events.
When the Mic button is pressed, i want to establish a connect to the device and read
audio. I can receive the Mic button events correctly so far.
bluetoothctl -- info FC:65:DE:E8:E8:FD
Name: Amazon Fire TV Remote
Alias: Amazon Fire TV Remote
Class: 0x00001f00
Paired: yes
Trusted: yes
Blocked: no
Connected: yes
LegacyPairing: no
UUID: Serial Port (00001101-0000-1000-8000-00805f9b34fb)
UUID: Human Interface Device... (00001124-0000-1000-8000-00805f9b34fb)
UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb)
Modalias: usb:v1949p0410d0304
sdptool browse FC:65:DE:E8:E8:FD
Browsing FC:65:DE:E8:E8:FD ...
Service Name: SPPSERVER
Service RecHandle: 0x20000002
Service Class ID List:
UUID 128: 00001101-0000-1000-8000-00805f9b34fb
Protocol Descriptor List:
"L2CAP" (0x0100)
"RFCOMM" (0x0003)
Channel: 6
Language Base Attr List:
code_ISO639: 0x656e
encoding: 0x6a
base_offset: 0x100
As You can see, the Remote exposes a Serial Port Profile.
I can connect to the service with:
sudo rfcomm connect /dev/rfcomm1 FC:65:DE:E8:E8:FD 1
...
Connected /dev/rfcomm1 to FC:65:DE:E8:E8:FD on channel 1
Press CTRL-C for hangup
I can use a teminal programm on /dev/rfcomm1 which comes up with a request from the remote:
AT+BRSF=253
At this point you should be able to answer the request and finally initiate the
recording on channel 6.
At this point i am stuck, because i get not further response
from the device.
Regards
Dezi
I am using Bluez 5.50; 5.48 was the version acquire-write became officially (non-experimentally) supported. Am I using the acquire-write / write feature properly?
On my Raspberry Pi Zero W:
pi#raspberrypi:~ $ bluetoothctl
[bluetooth]# power on
Changing power on succeeded
[bluetooth]# scan on
Discovery started
[bluetooth]# connect B8:27:E8:72:33:7A
Attempting to connect to B8:27:E8:72:33:7A
Connection successful
[DSD TECH]# menu gatt
[DSD TECH]# select-attribute 0000ffe1-0000-1000-8000-00805f9b34fb
[DSD TECH:/service0010/char0011]# acquire-write
[CHG] Attribute /org/bluez/hci0/dev_B8_27_E8_72_33_7A/service0010/char0011 WriteAcquired: yes
AcquireWrite success: fd 7 MTU 23
[DSD TECH:/service0010/char0011]# write("h")
[DSD TECH:/service0010/char0011]# write('h')
[DSD TECH:/service0010/char0011]# write(h)
[DSD TECH:/service0010/char0011]# write(0x68)
On my Arduino Nano connected to HM-10:
void setup()
{
Serial.begin(9600);
}
void loop() {
delay(10);
if (Serial.available())
{
char c = Serial.read();
Serial.println("Read value");
}
}
I use the iOS app named "Serial" which connects to my HM-10. I send the letter h over and read "Read value" on the arduino serial monitor. I do this directly before and after using the raspberry pi, on the same arduino serial monitor. The raspberry pi notifications never come thru. Yes, I am certain it is the same HM-10. It is the only HM-10 I have powered on in BLE range, and I cannot connect to the UUID while my phone is connected. (Actually, I submit connect B8:27:E8:72:33:7A to the raspberry pi, and keeps trying, and then disconnect from phone, and rpi automatically connects).
Thanks in advance!
When using gatt services with bluetoothctl, leave off the parentheses and just use:
write 0x68
acquire-write returns a file descriptor that can be used for writing to the GATT characteristic, usage of write will be locked. so either use acquire-write (which requires a write-without-response flag) or use write.
void WriteValue(array{byte} value, dict options)
Issues a request to write the value of the
characteristic.
Possible options: "offset": Start offset
"device": Device path (Server only)
"link": Link type (Server only)
"prepare-authorize": boolean Is prepare
authorization
request
Possible Errors: org.bluez.Error.Failed
org.bluez.Error.InProgress
org.bluez.Error.NotPermitted
org.bluez.Error.InvalidValueLength
org.bluez.Error.NotAuthorized
org.bluez.Error.NotSupported
fd, uint16 AcquireWrite(dict options) [optional]
Acquire file descriptor and MTU for writing. Usage of
WriteValue will be locked causing it to return
NotPermitted error.
For server the MTU returned shall be equal or smaller
than the negotiated MTU.
For client it only works with characteristic that has
WriteAcquired property which relies on
write-without-response Flag.
To release the lock the client shall close the file
descriptor, a HUP is generated in case the device
is disconnected.
Note: the MTU can only be negotiated once and is
symmetric therefore this method may be delayed in
order to have the exchange MTU completed, because of
that the file descriptor is closed during
reconnections as the MTU has to be renegotiated.
Possible options: "device": Object Device (Server only)
"MTU": Exchanged MTU (Server only)
"link": Link type (Server only)
Possible Errors: org.bluez.Error.Failed
org.bluez.Error.NotSupported
I tried bluetooth connection test in the Ubuntu under Vmware environment.
Ubuntu is 14.04 lts, Bluetooth is USB-dongle and BT stack is Bluez 5.35.
I don't use pulseaudio.
I used bluetoothctl command to scan, pairing and connection.
But the connection is fail. Below is the log of bluetoothctl
$ sudo bluetoothctl
[bluetooth]# power on
[bluetooth]# show
Controller 00:1A:7D:DA:xx:xx (public)
Name: ubuntu
Alias: ubuntu-0
Class: 0x00000000
Powered: yes
Discoverable: no
Pairable: yes
UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb)
UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
UUID: Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb)
Modalias: usb:v1D6Bp0246d0532
Discovering: no
[bluetooth]# scan on // Wait until found BT headset
[bluetooth]# scan off
[bluetooth]# devices
Device 11:11:22:xx:xx:xx Test
Device 0C:E0:E4:xx:xx:xx PLT_Legend
[bluetooth]# pair 0C:E0:E4:xx:xx:xx // try pairing with 0C:E0:E4:xx:xx:xx
Attempting to pair with 0C:E0:E4:xx:xx:xx
[CHG] Device 0C:E0:E4:xx:xx:xx Connected: yes
[PLT_Legend]# interfaces_added
[CHG] Device 0C:E0:E4:xx:xx:xx Modalias: bluetooth:v0055p0113d0067
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 00001108-0000-1000-8000-00805f9b34fb
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 0000110b-0000-1000-8000-00805f9b34fb
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 0000110c-0000-1000-8000-00805f9b34fb
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 0000110e-0000-1000-8000-00805f9b34fb
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 0000111e-0000-1000-8000-00805f9b34fb
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 00001200-0000-1000-8000-00805f9b34fb
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 82972387-294e-4d62-97b5-2668aa35f618
[CHG] Device 0C:E0:E4:xx:xx:xx ServicesResolved: yes
[CHG] Device 0C:E0:E4:xx:xx:xx Paired: yes
Pairing successful
[CHG] Device 0C:E0:E4:xx:xx:xx ServicesResolved: no
[CHG] Device 0C:E0:E4:xx:xx:xx Connected: no
[PLT_Legend]# connect 0C:E0:E4:xx:xx:xx
Attempting to connect to 0C:E0:E4:xx:xx:xx
[CHG] Device 0C:E0:E4:xx:xx:xxConnected: yes
Failed to connect: org.bluez.Error.Failed
I found above bluez doesn't have a2dp profile.
Actually, bluez5.x and pulseaudio is combined closely. If don't use pulseaudio, user has to add extra profile(a2dp, or hspag).
Below code is sample for add a2dpsink , a2dpsource and haspag.
#define A2DP_SOURCE_ENDPOINT "/MediaEndpoint/A2DPSource"
#define A2DP_SINK_ENDPOINT "/MediaEndpoint/A2DPSink"
#define HSP_AG_PROFILE "/Profile/HSPAGProfile"
#define PA_BLUETOOTH_UUID_HSP_AG "00001112-0000-1000-8000-00805f9b34fb"
#define PA_BLUETOOTH_UUID_A2DP_SOURCE "0000110a-0000-1000-8000-00805f9b34fb"
#define PA_BLUETOOTH_UUID_A2DP_SINK "0000110b-0000-1000-8000-00805f9b34fb"
static void register_profile_reply(DBusPendingCall *call, void *user_data)
{
//struct bluetooth_profile *profile = user_data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
DBusError derr;
dbus_error_init(&derr);
if (!dbus_set_error_from_message(&derr, reply)) {
printf("Profile %s registered", (char *)user_data);
goto done;
}
//unregister_profile(profile);
printf("bluetooth: RequestProfile error: %s, %s", derr.name,
derr.message);
dbus_error_free(&derr);
done:
dbus_message_unref(reply);
}
static DBusConnection *connection;
void btd_profile_add_hspag(const char *profile, const char *uuid)
{
DBusMessage *msg;
DBusMessageIter iter, opt;
DBusPendingCall *call;
connection = btd_get_dbus_connection();
msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
"org.bluez.ProfileManager1",
"RegisterProfile");
if( msg == NULL ) {
printf("%s : msg is null \n", __func__);
}
dbus_message_iter_init_append(msg, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &profile);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uuid);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
&opt);
dbus_message_iter_close_container(&iter, &opt);
if (!g_dbus_send_message_with_reply(connection, msg, &call, -1)) {
printf("%s:%s - fail g_dbus_send_message_with_reply() \n", __FILE__, __func__);
//unregister_profile(profile);
goto failed;
}
dbus_pending_call_set_notify(call, register_profile_reply, &profile,
NULL);
dbus_pending_call_unref(call);
failed:
dbus_message_unref(msg);
return;
}
void btd_profile_add(void)
{
btd_profile_add_hspag(HSP_AG_PROFILE, PA_BLUETOOTH_UUID_HSP_AG);
btd_profile_add_hspag(A2DP_SOURCE_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SOURCE);
btd_profile_add_hspag(A2DP_SINK_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SINK);
}
After that, the bluez has a2dp, hspag profile without pulseaudio.
I can check it with "show" command of the bluetoothctl.
[bluetooth]# show
Controller 00:1A:7D:xx:xx:xx
Name: ubuntu
Alias: ubuntu-0
Class: 0x000000
Powered: yes
Discoverable: no
Pairable: yes
UUID: Headset AG (00001112-0000-1000-8000-00805f9b34fb)
UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control (0000110e-0000-1000-8000-00805f9b34fb)
UUID: Generic Access Profile (00001800-0000-1000-8000-00805f9b34fb)
UUID: PnP Information (00001200-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
UUID: Audio Source (0000110a-0000-1000-8000-00805f9b34fb)
UUID: Audio Sink (0000110b-0000-1000-8000-00805f9b34fb)
Modalias: usb:v1D6Bp0246d0523
Discovering: no
The bluetooth connection still fail even though a2dp profile is added.
Through btmon trace, the rfcomm connection is disconnected, and next, l2cap connection is also disconnected.
I don't know what i'm missing.
What do i need other to run bluez 5.35 without pulseaudio?
Log shows that your "PLT_Legend" device supports A2DP SINK role, so your Ubuntu should act as A2DP SOURCE role. To make it work you need an working profile implementation.
You may not need complete implementation of A2DP source profile for sourcing the audio data, but at least you need to register basic functionality to make bluetoothd happy.
The below image is directly copied from here.
In the above sequence you can see that bluetoothd calls "SelectConfiguration" and "SetConfiguration" when a new device with A2DP capability is connected.
As you have observed, connection state is initially moved to connected and later fallback to "no". This is because, bluetoothd attempts to connect with the profiles (SDP service discovery protocol) after getting the low level connection. Once the low level connection is successful, the device is marked as connected and SDP proceeds.
During the SDP bluetoothd tries to get the capability of your device (ubuntu in this case) and negotiates with the end device (PLT_Legend) on the codecs support using "SelectConfiguration" and selects one using "SetConfiguration". Once this handshake is success, bluetoothd marks A2DP profile is connected.
So with your dummy registration of profiles, as it couldn't find the methods and proper codec returns, it marks the connection is failed and terminates the connection between Ubuntu and device.
If you don't want to use pulseaudio, you can try using bluez-alsa https://github.com/Arkq/bluez-alsa and start to listen on A2DP profiles. I think this package is already available in ubuntu repo, you can try
sudo apt-get install bluez-alsa
AFAIK, pulseaudio is not tightly bound with bluetooth, you can still implement your own A2DP imeplementation in way bluetoothd understands.
Note, bluez-alsa uses open source fdk-aac for AAC encoding and decoding.
How to set scan parameters and disable the filter duplicates, so that I can receive all advertisement from the controller ?
StartDiscovery API only notifies, whenever new device is identified but I want to set filter duplicate to disabled, so that I can receive each and every advertisement from the controller?.
But I didn't find any DBus API to set the scan parameters nor set scan enable API.
My Goal is simple I need get notify each advertisement received on controller to my client app, How can I do that with Bluez?
Note : I might missing some basic points because new to bluetooth and bluez.
In the below output you can see that the Device "Parthiban" is already present under /org/bluez/hci0/dev_44_D8_84_02_A3_17. I have started the scan which in turn triggers "StartDiscovery()" method and the same device is updated with RSSI value.
root#mx6q:~# bluetoothctl
[NEW] Controller 5C:F3:70:6E:26:02 Adapter [default]
**[NEW] Device 44:D8:84:02:A3:17 Parthiban**
[NEW] Device 2C:F0:A2:26:D7:F5 iPhone tteam
[NEW] Device 78:F8:82:10:E7:0C Nexus 5X
[bluetooth]# scan on
Discovery started
[CHG] Controller 5C:F3:70:6E:26:02 Discovering: yes
**[CHG] Device 44:D8:84:02:A3:17 RSSI: -52**
So you can use "g_dbus_connection_signal_subscribe" on the interface "org.freedesktop.DBus.Properties" for "PropertiesChanged" signal.
while(g_variant_iter_loop(&iter, "{sv}", &property, &value)) {
if(strcasecmp(property, "RSSI") == 0) {
/*
* - Extract the device address from object path
* /org/bluez/hci0/dev_44_D8_84_02_A3_17
* - Play with the device
*/
}
Environment: Bluez 5.14, Linux 3.1, USB Plugable BLE radio, TI BLE keyfob (CC2541 dev kit)
Linux Device <---hci----> USB BLE Radio
We enabled key press events on TI keyfob using gatttool and started to listen for events
gatttool -b [hardware ID] --char-write-req -a [handle] -n [value] --listen
(gatttool -b 90:59:AF:09:E1:5D --char-write-req -a 0x0048 -n 0100 --listen)
Pressing buttons on the keyfob and see these events
Notification handle = 0x0047 value: 02
Notification handle = 0x0047 value: 00
Notification handle = 0x0047 value: 02
Hence we can receive the key press events from the Keyfob through the Bluez stack
Objective:
We need to catch the GATT Disconnect Event i.e. When we remove the battery from the keyfob sooner or later the GATT connection is broken. We would like to receive a disconnect event from Bluez stack. Bluez has this capability since Android supports GATT disconnect event which is built over Bluez.
Question:
How do we receive the GATT Disconnect event using Bluez command line hcitool/gatttool or Bluez API.
Watch for G_IO_HUP and shutdown gracefully.
chan = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
opt_psm, opt_mtu, connect_cb, &gerr);
if (chan == NULL) {
log_printf(LOG_LEVEL_ERROR,"%s: chan is NULL\n",__func__);
log_printf(LOG_LEVEL_ERROR,"%s\n", gerr->message);
g_error_free(gerr);
g_main_loop_quit(event_loop);
} else {
log_printf(LOG_LEVEL_INFO,"Connected to %s\n",opt_dst);
g_io_add_watch(chan, G_IO_HUP, channel_watcher, NULL);
}