AttributeError: 'NoneType' object has no attribute 'scan' - bluetooth-lowenergy

`I am trying to scan for devices advertising the UART service using Micropython on esp32. but I get AttributeError: 'NoneType' object has no attribute 'scan'
below is my code:
# Initialize and enable the BLE radio.
ble = ubluetooth.BLE()
ble.active(True)
# Create a BLE scanner object.
scanner = ble.gap_scan(10, 30000, 30000)
# Scan for devices advertising the UART service.
print('Scanning for devices advertising the UART service...')
devices = scanner.scan(10)
# Connect to the first device with the matching UART service UUID.
for device in devices:
for advertised_service in device.services:
if advertised_service.uuid == UART_SERVICE_UUID:
# Connect to the device.
print(f'Connecting to device {device.name}...')
connection = ble.connect(device)
# Wait for the connection to be established.
while not connection.is_connected:
pass
print('Connection established!')
# Stop scanning.
scanner.stop()
break
if connection.is_connected:
break
`

Your code reads:
# Create a BLE scanner object.
scanner = ble.gap_scan(10, 30000, 30000)
# Scan for devices advertising the UART service.
print('Scanning for devices advertising the UART service...')
devices = scanner.scan(10)
You're using the gap_scan() method incorrectly. According to the documentation, when the scanner detects a device it calls the callback function. You're getting an error because gap_scan() doesn't return anything, which is consistent with the documentation.
You need to register an event handler in order to see the results of a scan. So:
def ble_callback_handler(event, data):
if event == _IRQ_SCAN_RESULT:
# A single scan result. Do whatever you need with this
addr_type, addr, adv_type, rssi, adv_data = data
elif event == _IRQ_SCAN_DONE:
# Scan duration finished or manually stopped.
# register a callback handler
ble.irq(ble_callback_handler)
# start scanning
ble.gap_scan(10, 30000, 30000)

Related

How Can Peripheral Get Notification on Central Bond Delete

Peripheral: Nordic nRF52840 chipset with Zephyr
Central: Android smartphone
Bond is created and "pairing_complete" callback is called in peripheral.
But when manually delete the bonding(from Bluetooth > [peripheral device]Unpair), how can the peripheral gets a notification?
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
};
struct bt_conn_auth_cb cb = {
.cancel = cancel,
.oob_data_request = NULL,
.pairing_confirm = NULL,
.passkey_confirm = pass_confirm,
.passkey_display = pass_display,
.passkey_entry = NULL,
};
bt_conn_auth_cb_register(&cb);
struct bt_conn_auth_info_cb info_cb = {
.bond_deleted = bond_deleted, // ------> not getting called when central deletes the pairing
.pairing_complete = pairing_complete,
.pairing_failed = pairing_failed,
};
bt_conn_auth_info_cb_register(&info_cb);
The callbacks are implemented as usual.
My question is, when user deletes the bonding(unpair) from smartphone:
Why the peripheral not getting notification in "bond_deleted' callback?
Is there any other way to get this notification?
Or is this BLE concept?
FYI:
"disconnected" callback is getting called
After disconnection, if I connect from another central, peripheral gets the "bond_deleted" called before bonded
The bond_deleted callback seems only being called when the bond removal is initiated by the local device, as seen here: https://github.com/zephyrproject-rtos/zephyr/pull/26876 where it was introduced. Maybe this callback is called for you when you bond a new central because the oldest one is being removed.
Naturally, the peripheral can't be notified of the bond removal in the central in case the peripheral is disconnected (e.g. out of range) when being unbonded in the central.
If there is a connection ongoing while the central unbonds, then unfortunately it just disconnects without informing the peripheral that the central has removed its bond. The next time it connects (if it ever does so), it will need to perform a new pairing attempt in case it needs to communicate securely.
To solve the issue that the peripheral is not notified of the unbonding attempt, there is a BLE service for that: the Bond Management Service. See https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/samples/bluetooth/peripheral_bms/README.html for an nRF Connect SDK implementation. I'm not sure if Android implements it though (I would be surprised if it did).

How to handle the device watcher "cache" of old devices on start-up?

I have one BLE application.
When I start the device scanning, the DeviceWatcher.Added event will call immediately and shows the previously connected devices which is currently powered off. But in the DeviceWatcher.Removed event it will be cleared.
How can I prevent this situation. In my application I am trying to connect the device immediately when ever there is the device listed in the DeviceWatcher.Added event. I don't want to wait till the DeviceWatcher.EnumerationCompleted event.
Because of this implementation, the connection API BluetoothLEDevice bluetoothLEDevice = BluetoothLEDevice::FromIdAsync(GetId()).get(); is returning success. And in the service scan API GattDeviceServicesResult result = m_BluetoothLEDevice.GetGattServicesAsync(BluetoothCacheMode::Uncached).get(); I am getting GattCommunicationStatus::Unreachable status.
I need this status in the initial time of scanning. Or there is any other way I can check the device is unreachable or not?
The sample written here is in C#, you could find the C++ replacement in the learn.microsoft.com
You could get all the paired BLE devices like this.
var pairedBleDevices = await DeviceInformation.FindAllAsync(BluetoothLEDevice.GetDeviceSelectorFromPairingState(true)); # Return all the paired Bluetooth LE devices
Now, if you want to remove the pairing of a specific device, you could loop through the pairedBleDevices and find your removal device by matching specific property, let's say device name or address.
foreach (var device in pairedBleDevices )
{
if (!device::Name.Contains("myDevice")) continue;
await device.Pairing.UnpairAsync();
break;
}
Now, as you have all the previously paired LE devices with properties, as Mike suggested, you could use BluetoothLEAdvertisementWatcher to discover BLE devices and filter the advertisement by matching the BluetoothAddress(from the paired device). If you find a new device, pair the device or execute the GATT operation and start communicating.
You are getting GattCommunicationStatus::Unreachable that's probably the device you are trying to communicate with is in sleep mode. So the best way is to capture the advertisement first using BluetoothLEAdvertisementWatcher and, after that, initiate the pairing or GATT operation.

Bluetooth Low Energy data transfer with nRF52840

I am attempting to pass motion data (accelerometer, gyroscope,...) from an IMU to my computer over a Bluetooth Low Energy (BLE) connection. I purchased the FXOS8700 + FXAS21002 to generate motion data and am using a wired I2C connection to pass that data to my BLE board, an nRF52840. The I2C connection works and I can get data off the nRF52840 via a wired connection. I have also managed to establish a Bluetooth connection between my BLE board and my computer and can view the BLE characteristics, but I can't figure out how to program the nRF52840 to write my motion data into these characteristics to pass them over Bluetooth.
Below is the code I have used to establish an I2C connection and create the BLE connection. Missing is the code to create BLE characteristics.
# Import ble libraries
import _bleio
import adafruit_ble
from adafruit_ble.advertising.standard import Advertisement
from adafruit_ble.services.standard.device_info import DeviceInfoService
# Import libraries for the FXOS8700 accelerometer and magnetometer
import time
import board
import busio
import adafruit_fxos8700
# CircuitPython <6 uses its own ConnectionError type. So, is it if available. Otherwise,
# the built in ConnectionError is used.
connection_error = ConnectionError
if hasattr(_bleio, "ConnectionError"):
connection_error = _bleio.ConnectionError
# PyLint can't find BLERadio for some reason so special case it here
ble = adafruit_ble.BLERadio() # pylint: disable=no-member
# Initialize I2C bus and device
i2c = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_fxos8700.FXOS8700(i2c)
isConnected = 0
while not isConnected:
print("Scanning...")
for adv in ble.start_scan(Advertisement, timeout=5):
name = adv.complete_name
if not name:
continue
isConnected = 1
print("Connected")
break
# Stop scanning whether or not we are connected
ble.stop_scan()
print("Stopped scan")
while True:
# Read acceleration and magnetometer
accel_x, accel_y, accel_z = sensor.accelerometer
mag_x, mag_y, mag_z = sensor.magnetometer
# Write acceleration and magnetometer data to BLE characteristics...
How do I write data into a BLE characteristic and send that data over Bluetooth? Do I need to create a new BLE characteristic or service? I feel that I am missing something fundamental here...
Additional information:
I am using the ble() function in MATLAB to connect to the nRF52840 and read the BLE characteristic data. I was initially trying to pass every single measurement over Bluetooth (likely requiring a more complex program with data buffers), but at this point I would be happy simply being able to read the most recent measurement.
Since the BLE board I'm using is so popular, I expected to find numerous examples of data transfer over Bluetooth, but I haven't found any examples of sending data with BLE. There are numerous examples using a BLE-UART connection (not visible to MATLAB) or sending data to the BLE board, but none sending data from the BLE board, except via this UART method (but I can't find a way to access that data).

Bluez BLE Connections Monitoring using DBUS-Python

I was able to advertise the BLE and setup GATT Services and Characteristics by following the "example_advertisement" and "example-gatt-server" in Bluez Examples. How can I know from DBUS when a BLE client is connected and when it is disconnected, using similar DBUS binding for Python? Which DBUS API do I look into?
There is another example that you can look at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/test/test-discovery
When BlueZ/DBus learns of a new remote device, then the InterfacesAdded signal gets sent.
When a remote device goes from disconnected, to connected. Then that is a property change on the device and the PropertiesChanged signal gets sent.
This is why there is the code in the above example they use add_signal_receiver to add callbacks for both signals.
bus.add_signal_receiver(interfaces_added,
dbus_interface = "org.freedesktop.DBus.ObjectManager",
signal_name = "InterfacesAdded")
bus.add_signal_receiver(properties_changed,
dbus_interface = "org.freedesktop.DBus.Properties",
signal_name = "PropertiesChanged",
arg0 = "org.bluez.Device1",
path_keyword = "path")
As a side note, the DBus bindings used in the Buez examples are not the only ones available:
https://www.freedesktop.org/wiki/Software/DBusBindings/

How to connect embedded gps device to gpsd

My questions are about my problem interfacing to the 'device' side of gpsd.
I have a GPS device that produces NMEA 0183 output via an RS232 / UART connection, sitting on an embedded board. My problem is that I want to get the data from this device into 'gpsd' running in linux on an SoC on another 'System' board. The only connection I have to get the data from the embedded board with the device is an I2c connection, and I can create an app on the System board that will pull the NMEA message data from the embedded board, across the I2c interface.
My question is how best to get these NMEA messages from my app on the System board into gpsd running on my System board, so that I can use gpsd to 'consolidate' and 'distribute' the gps data to other client applications?
It looks like possibilities are using a tcp or udp device connection into gpsd, or to use a pseudo-terminal (pty) connection as is apparently used for regression testing.
I tried opening a 'raw' pseudo-terminal pair in my app, and adding the pty slave device to gpsd via gpsd's control socket connection. But although gpsd appears to recognize the device as a pseudo-terminal (with major node number 136) and add the pty slave device (/dev/pts/2 in this case), open the pty slave device, and 'activate' the device, it never appears to read any of the NMEA messages coming across the pty slave.
I see the following debug output from gpsd:
root#abcd-efgh:~# gpsd -n -N -D12 -F /var/run/gpsd.sock
gpsd:SPIN: control socket /var/run/gpsd.sock is fd 3
gpsd:PROG: control socket opened at /var/run/gpsd.sock
gpsd:INFO: launching (Version 3.11~dev)
gpsd:IO: opening IPv4 socket
gpsd:SPIN: passivesock_af() -> 4
gpsd:IO: opening IPv6 socket
gpsd:SPIN: passivesock_af() -> 5
gpsd:INFO: listening on port 2947
gpsd:PROG: shmat() succeeded, segment 0
gpsd:PROG: shared-segment creation succeeded,
gpsd:INFO: running with effective group ID 0
gpsd:INFO: running with effective user ID 0
gpsd:INFO: startup at 2016-08-31T16:48:39.000Z (1472662119)
gpsd:UNK: select waits
gpsd:SPIN: select() {3 4 5} -> { 3 } at 1472662124.273340 (errno 0)
gpsd:INFO: control socket connect on fd 6
gpsd:CLIENT: <= control(6): +/dev/pts/2\x0a
gpsd:INFO: <= control(6): adding /dev/pts/2
gpsd:INFO: stashing device /dev/pts/2 at slot 0
gpsd:INFO: opening GPS data source type 6 at '/dev/pts/2'
gpsd:INFO: speed 115200, 8N1
gpsd:SPIN: open(/dev/pts/2) -> 7 in gpsd_serial_open()
gpsd:INFO: gpsd_activate(2): activated GPS (fd 7)
gpsd:INFO: device /dev/pts/2 activated
At that point gpsd just appears to "hang" waiting on messages...
But although GPS messages are then being written from the pty master (by the app running on the System board that pulls the messages from the device), gpsd never appears to read them... If I connect with 'gpsmon' or 'gpspipe' to see what messages are coming across, I see no JSON or raw message output like I would if I had a serial device (ttySx) directly connected to gpsd. I'm not sure if gpsd has added my pty slave file descriptor to the list of descriptors it 'select()'s on.
I've also tried writing another 'dummy' app to open the pty slave device in place of gpsd and read what's coming across the pseduo-terminal connection from the 'main' app that is writing the NMEA messages, and the dummy app appears to get all of the messages correctly. So I'm not sure why gpsd isn't seeing them.
Is the pty connection a valid way to approach this?
Do I have to start up gpsd from my application, passing it the slave pty device path in gpsd's runstring options, instead of connecting the pty device via the control socket 'add device' message?
Or would the 'tcp' device connection be a more standard way to interface the messages from the device, via my main application? Can I then open a local socket connection from my app, and feed the 'tcp://localhost:port' in an 'add device' message across the control socket connection? Or does the tcp socket connection have to already exist when gpsd is launched?
UPDATE: It does appear my pty interface works, as long as I run gpsd with the pts slave device in the runstring, instead of trying to add it with an "add device" message through the control socket. I'm now seeing the NMEA messages I'm sending through from my application being used by gpsd, and can run gpsmon and see location information updating.

Resources