Distance to a Bluetooth device can be measured using RSSI value. The following script will help you locate nearby unique BLE devices within a selected range.
This script scans for nearby unique Bluetooth devices within the given range using a well-known RSSI to distance formula.
Smart Sensor Devices was awarded the Nordic Growth Company award from UC for success in the financial year 2019/2020. The company is doing steady and robust development and growth. The award was given for efforts during the previous financial year. The company sees a continued positive development and sales have increased compared with the previous financial year.
“The development is very positive with steady growth during the current financial year. Demand for our products and services has increased in the recent period for all our offerings, We are very gratefully for all our new customers” says Axel Hammar, Founder & CEO of Smart Sensor Devices.
Added a new command AT+CLEARNOTI that will clear notification for the selected handle. For example AT+CLEARNOTI=0012
Updated command for AT+GAPCONNECT. Now you can set Connection interval,Slave latency,Connection supervision timeout while connecting to a peripheral.
Understand BLE connection parameters
For a BLE connection, The connection parameters determine when and how the Central and a Peripheral in a link transmits data. The Central always sets the connection parameters; however, the Peripheral can send a Connection Parameter Update Request that the Central can accept or reject.
There are basically three different parameters:
Connection interval: Defines how often the Central will ask for data from the Peripheral. It contains minimum and maximum connection interval values.
The parameter value has to be chosen with a balance of throughput and power consumption in mind. A high connection interval value (e.g. 4 seconds) will decrease power consumption and reduce data throughput, and vice versa.
Therefore, if you want to increase the data throughput, you can decrease the connection interval value, but keep in mind that this will also increase power consumption.
Slave latency: slave latency can be applied to help the peripheral (slave) device reduce power consumption further. This parameter is useful to avoid changing connection parameters frequently to achieve both high-speed data transfer and low power consumption when idle.
For example, suppose there is a 30 ms connection interval with a slave latency of 4. In that case, the connection can handle data transfers with 30 ms connection intervals, and when idle, it sends empty packets to keep the connection only once every 150 ms (on the slave side).
Connection supervision timeout: This timeout is determined from the last data exchange until a link is considered lost. A Central will not start trying to reconnect before the timeout has passed, so if you have a device that goes in and out of range often, and you need to notice when that happens, it might make sense to have a short timeout.
To meet the demands of users, the BleuIO team will continue to update and add new features. To find out more about the updates of the dongles new firmware 2.0.6, please visit our Getting Started Guide.
Bluetooth ranging technology is very popular. There are many localization systems that exist based on beacons. Beacon technology usually estimates the distance between devices using the received signal strength (RSSI).
Bluetooth can be an excellent way to narrow down a search area at close distances when tracking something. This feature can be used in several fields. such as Secure Locks for Buildings and Automotive, Asset localization & tracking, Indoor navigation etc
GPS tracking isn’t excellent at giving accurate measurements of the close distance, especially in the indoor environment. On the other hand, Bluetooth is excellent in short ranges because the waves can go through walls. This might fill the gap that GPS tracking has when tracking devices in indoor spaces.
However, most calculations of the distance between two Bluetooth devices are estimates. It’s hard to determine the exact distance between two Bluetooth devices because many factors affect the calculations. Despite the challenges, there are methods to determine the distance between two Bluetooth devices with an accuracy of at least 60-80%.
The ranging method is simple to implement, and it has the formula to calculate the distance between two Bluetooth devices. As the name suggests, both devices need to be within Bluetooth range to estimate the distance.
This article will share a simple script written in JavaScript to determine nearby Bluetooth devices and their distance in meters.
This script scans for nearby Bluetooth devices and gets an approximation of the distance by using the well-known RSSI to distance formula.
The script will an index.html and script.js file. Index.html is just has a connect and scan for device button. upon connecting we will be able to scan for nearby devices and. Once the scanning is completed we will be able to see a list of devices and their distance from my computer.
The script.js file uses bleuio javascript library to connect and scan for BLE devices. Once we get the device list, we try to sort it out by RSSI value and convert RSSI value to distance. Finally we print the result into a table.
Here is the script.js file
import * as my_dongle from 'bleuio'
document.getElementById('connect').addEventListener('click', function(){
my_dongle.at_connect()
})
/*
Functions to converts rssi to distance
read more at
https://iotandelectronics.wordpress.com/2016/10/07/how-to-calculate-distance-from-the-rssi-value-of-the-ble-beacon/
*/
const getDistance =(rssi=>{
let n=2
let mp=-69
return 10 ** ((mp - (rssi))/(10 * n))
})
document.getElementById('scan').addEventListener('click', function(){
var element = document.getElementById("scanning");
element.classList.remove("d-none");
my_dongle.at_central().then((data)=>{
my_dongle.at_gapscan(4,false).then((dev)=>{
//convert array string to array of object with key value
const formated = dev.map((item) => {
const [ id, dev,devid,none,rssi,rssival,devname ] = item.split(' ');
return { id, dev,devid,none,rssi,rssival,devname};
});
//array list unique
let uniqueArr= formated.filter(y=>y.devname!=undefined)
//sort based on rssi value
uniqueArr.sort((a, b) => a.rssival > b.rssival && 1 || -1)
let withDistance= uniqueArr.map(r=>{
r.distance=getDistance(r.rssival).toFixed(2)+' meter'
return r
})
//generate output
let mytable = `<h2>Device List</h2>
<table class='table table-striped table-bordered'>
<tr>
<th>Device</th>
<th>RSSI</th>
<th>Distance</th>
</tr>`;
withDistance.map(j=>{
mytable += "<tr><td>" +j.devid+" - "+ j.devname + "</td><td>"+ j.rssival+"</td><td>"+j.distance+"</td></tr>";
})
mytable += "</table>";
document.getElementById("deviceList").innerHTML = mytable;
element.classList.add("d-none");
})
})
})
To run this script , we can use a web bundler called parcel. https://parceljs.org/
lets go inside the folder and in terminal type.
parcel index.html
The script will scan for five seconds for nearby devices. You can update the value based on your requirements.
This tutorial will show how to transfer files wirelessly over the Bluetooth Low Energy protocol. We will use two BleuIO dongles for this project—one for sending and another one for receiving. The sender dongle will be in central mode, while the receiver dongle will be in peripheral mode.
We have already created two python scripts for sending and receiving. You can get the source code from
First, connect two BleuIO dongles to your computer.
Note down the COM port for each dongle. You can find the port using device manager.
Try to find receiver dongle MAC id. To do that, start advertising your receiver dongle and note down the MAC id. Follow the video if you need more details on how to do it.
Open file_recieve.py and file_transfer.py files. Update COM port and MAC id where necessary.
Here is the file_recieve.py
import serial
import time
your_com_port = "COM6" # Change this to the com port your dongle is connected to.
file_name = "result.png" # Change this to match the file type you are recieving
connecting_to_dongle = True
trying_to_connect = False
print("Connecting to dongle...")
# Trying to connect to dongle until connected. Make sure the port and baudrate is the same as your dongle.
# You can check in the device manager to see what port then right-click and choose properties then the Port Settings
# tab to see the other settings
while connecting_to_dongle:
try:
console = serial.Serial(
port=your_com_port,
baudrate=57600,
parity="N",
stopbits=1,
bytesize=8,
timeout=0,
)
if console.is_open.__bool__():
connecting_to_dongle = False
except:
print("Dongle not connected. Please reconnect Dongle.")
time.sleep(5)
print("Connected to Dongle.")
file_data = ""
file_transfer_done = False
connected = "0"
line = ""
while 1 and console.is_open.__bool__() or not file_transfer_done:
console.write(str.encode("AT+DUAL"))
console.write("\r".encode())
print("Putting dongle in Dual role.")
time.sleep(0.1)
console.write(str.encode("AT+ADVSTART"))
console.write("\r".encode())
time.sleep(0.1)
print("Starting advertising and awaiting connection from other dongle...")
while connected == "0":
dongle_output2 = console.read(console.in_waiting)
time.sleep(2)
if not dongle_output2.isspace():
if dongle_output2.decode().__contains__("\r\nCONNECTED."):
connected = "1"
print("Connected!")
if dongle_output2.decode().__contains__("\r\nDISCONNECTED."):
connected = "0"
print("Disconnected!")
dongle_output2 = " "
while connected == "1" or not file_transfer_done:
time.sleep(0.2)
dongle_output3 = console.read(console.in_waiting)
if not dongle_output3.isspace():
if dongle_output3.__contains__(str.encode("\r\nDISCONNECTED.")):
print("Disconnected!")
connected = "0"
elif dongle_output3.__contains__(str.encode("[DONE]")):
file_transfer_done = True
print("File transfer complete!\r\n")
fo = open(file_name, "wb")
hex = bytes.fromhex(file_data)
fo.write(hex)
fo.close()
print("Exiting script...")
exit()
elif dongle_output3.__contains__(str.encode("[Received]:")):
line = dongle_output3.decode()
line = line.replace("\r", "")
line = line.replace("\n", "")
line = line.replace("[Received]:", "")
line = line.replace(" ", "")
file_data += line
print(line)
dongle_output3 = ""
msg = ""
Set the file type that you are expecting to receive. For example, if you are expecting a jpg file, change file_name on file_recieve.py to result.jpg, and for a text file, you can rename it to result.txt
Here is the file_transfer.py
import serial
import time
target_dongle_mac_address = (
"[0]40:48:FD:E5:2D:AF" # Change this to the peripheral's mac address.
)
your_com_port = "COM25" # Change this to the com port your dongle is connected to.
connecting_to_dongle = True
trying_to_connect = False
file_name = "test.txt"
print("Connecting to dongle...")
# Trying to connect to dongle until connected. Make sure the port and baudrate is the same as your dongle.
# You can check in the device manager to see what port then right-click and choose properties then the Port Settings
# tab to see the other settings
while connecting_to_dongle:
try:
console = serial.Serial(
port=your_com_port,
baudrate=57600,
parity="N",
stopbits=1,
bytesize=8,
timeout=0,
)
if console.is_open.__bool__():
connecting_to_dongle = False
except:
print("Dongle not connected. Please reconnect Dongle.")
time.sleep(5)
print("Connected to Dongle.")
connected = "0"
while 1 and console.is_open.__bool__():
console.write(str.encode("AT+DUAL"))
console.write("\r".encode())
time.sleep(0.1)
print("Putting dongle in Dual role and trying to connect to other dongle.")
while connected == "0":
time.sleep(0.5)
if not trying_to_connect:
console.write(str.encode("AT+GAPCONNECT="))
console.write(str.encode(target_dongle_mac_address))
console.write("\r".encode())
trying_to_connect = True
dongle_output2 = console.read(console.in_waiting)
time.sleep(2)
print("Trying to connect to Peripheral...")
if not dongle_output2.isspace():
if dongle_output2.decode().__contains__("\r\nCONNECTED."):
connected = "1"
print("Connected!")
time.sleep(10)
if dongle_output2.decode().__contains__("\r\nDISCONNECTED."):
connected = "0"
print("Disconnected!")
trying_to_connect = False
dongle_output2 = " "
while connected == "1":
dongle_output3 = console.read(console.in_waiting)
want_to_exit = input(
"Press Enter to start sending file or 'exit' to quit script.\n\r>> "
)
want_to_exit = want_to_exit.upper()
if "EXIT" in want_to_exit:
print("Exiting script...")
exit()
hex_to_send = ""
fo2 = open(file_name, "rb")
print("Sending file. Please wait...")
while (byte := fo2.read(1)) :
hex_to_send += byte.hex().upper()
if len(hex_to_send) >= 200:
# my_dongle.at_spssend(hex_to_send)
console.write(str.encode("AT+SPSSEND=" + hex_to_send + "\r"))
time.sleep(0.2)
hex_to_send = ""
if len(hex_to_send) != 0:
# my_dongle.at_spssend(hex_to_send)
console.write(str.encode("AT+SPSSEND=" + hex_to_send + "\r"))
time.sleep(0.2)
fo2.close()
console.write(str.encode("AT+SPSSEND=[DONE]\r"))
print("File transfer complete!\r\n")
print("Exiting script...")
exit()
Keep the file in the same directory with file_transfer.py and change the file name accordingly.
Now run the script file_recieve.py using a terminal. It will start advertising and will be ready to receive.
Now run the file_transfer.py script.
Once both the dongles are connected, you will be asked to send the file from the file transfer script.
The receiver dongle will give you a confirmation once received, and you will find the file stored in the same folder with the receiver script.
Finally, you can check if you received the file correctly by running a checksum.
Please follow the video if you have difficulty in understanding.
Smart Sensor Devices is announcing a firmware update v2.0.5 for BleuIO and Smart USB dongle 2.0. We invite all the users to apply the updated firmware. The new firmware will be available to download on 2nd July 2021, at https://www.bleuio.com/getting_started/docs/firmware/
Added features:
Added a new command ATASPS that will allow you to choose if the SPS responses will be shown as ASCII or Hex. ASCII is shown by default at startup.
Bug fixes
Fixed a bug where if you sent more than 244 characters at once before sending a carriage return (or pressed Enter) the dongle would restart.
To meet the demands of users, the BleuIO team will continue to update and add new features. To find out more about the updates of the dongles new firmware 2.0.5, please visit our Getting Started Guide.
Smart Sensor Devices is announcing a firmware update v2.0.4 for BleuIO and Smart USB dongle 2.0. We invite all the users to apply the updated firmware. The new firmware will be available to download on 21st May 2021, at https://www.bleuio.com/getting_started/docs/firmware/
Added features:
Added two new AT command for writing without response. AT+GATTCWRITEWR for ASCII and AT+GATTCWRITEWRB for hex.
Added a new command AT+GETSERVICESONLY that will discover only all the services of the connected peripherals.
Added a new command AT+GETSERVICEDETAILS that will discover all the characteristics and descriptors of a selected service. Must run AT+GETSERVICESONLY command first to get the service handle.
To meet the demands of users, the BleuIO team will continue to update and add new features. To find out more about the updates of the dongles new firmware 2.0.4, please visit our Getting Started Guide.
Smart Sensor Devices is announcing a firmware update v2.0.3 for BleuIO and Smart USB dongle 2.0. We invite all the users to apply the updated firmware. The new firmware will be available to download at https://www.bleuio.com/getting_started/docs/firmware/
Added features:
Added new AT command ATDS that turns on (ATDS0) or turns off (ATDS1) auto-discovery of services from the device you are connecting to or when you’re in DUAL mode, and a device connects to you. Auto discovers services are on by default.
Added a new command AT+GAPDISCONNECTALL that disconnects all current connections.
Bug fixes
Fixed a bug where the services that were being auto-discovered upon a connection event was from the connection set in target connection instead of the current connection.
Fixed a bug where you had to put a small timeout between the actual command and the carriage return (‘\r’) to run a command when using scripts to communicate with the dongle. You should now be able to send the command and the return character at the same time.
Updated the response from a successful AT+GAPDISCONNECT command. It should now reply with a ‘handle_evt_gap_disconnected: conn_idx=conn_idx address=mac_address_of_disconnected_device.’ and then the ‘DISCONNECTED.’ line for easily discerning which device has been disconnected.
To meet the demands of users, the BleuIO team will continue to update and add new features. To find out more about the updates of the dongles new firmware 2.0.3, please visit our Getting Started Guide.
Smart Sensor Devices is announcing a firmware update v2.0.2 for BleuIO and Smart USB dongle 2.0. We invite all the users to apply the updated firmware. The new firmware will be available to download on 7th April 2021, at https://www.bleuio.com/getting_started/docs/firmware/
Added features:
Added new AT command ATA that hides (ATA0) or shows (ATA1) ASCII values from Notification, Indication, or GATT Read responses. ASCII values are shown by default.
Bug fixes
Fixed a bug where running a scan and stopping it repeatedly would, in rare cases, cause a hard restart of the dongle.
To meet the demands of users, the BleuIO team will continue to update and add new features. To find out more about the updates of the dongles new firmware 2.0.2, please visit our Getting Started Guide.
Bluetooth low energy technology offers a suitable way of connecting smart devices. However, despite the convenience, you can bear witness that the range offered can be a little limiting. Sometimes the connection tends to drop or lag when you move a little further away from the device. Fortunately, it’s easy to overcome this range limitation with the Bluetooth repeater.
This article will explain how to create a BLE Repeater using BLE USB dongle called BleuIO and python.
The BleuIO is Bluetooth low energy solution that can be used to create new BLE 5.0 applications in the fastest and easiest way. Using this dongle’s multi-connection feature, we will make a simple repeater where one dongle scans nearby devices data and sends it to the repeater. At the same time, the repeater passes the data to the receiver dongle. And that’s how a repeater will help us overcome the range limitation.
For this project, sender dongle will scan for air quality data from HibouAir device and pass the advertised data along with timestamp to the repeater. The repeater dongle will be connected to a Raspberry pi which will forward data to the receiver dongle.
We have already created a sample script in python, which will help us to do the task.
Let’s start by cloning the repository from https://github.com/smart-sensor-devices-ab/bleuio_repeater_example
Once you cloned the script, you will find three different python script called
repeater_example_reciever_dongle.py
repeater_example_repeter_dongle.py
repeater_example_sender_dongle.py
We need to update the ports on those scripts manually.
repeater_example_reciever_dongle.py
import time
from bleuio_lib.bleuio_funcs import BleuIo
reciever_dongle_port = "COM74" # Change this to your dongle's COM port
mac_addr_to_repeater = (
"[0]40:48:FD:E5:2D:74" # Change this to your repeater dongle's mac address
)
buffer = ""
connected = False
connecting = ""
reciever_dongle = BleuIo(port=reciever_dongle_port)
reciever_dongle.start_daemon()
print("Dongle found.")
def save_msg(buffer):
"""
Parses incomming data string for just the data and prints it out.
"""
result = buffer
result_array1 = result.split("\r\n")
result_array = result_array1[2].split(" ")
msg_to_save = str(result_array[0])
print("Recieved = " + msg_to_save)
try:
reciever_dongle.at_dual()
ready = input(
"Press enter to connect to the repeater dongle. (This should be connected first)."
)
print("Connecting...")
reciever_dongle.at_gapconnect(mac_addr_to_repeater)
time.sleep(5)
while not connected:
connected_status = reciever_dongle.ati()
if "\r\nConnected" in connected_status[0]:
connected = True
break
if "\r\nNot Connected" in connected_status[0]:
reciever_dongle.at_gapconnect(mac_addr_to_repeater)
time.sleep(5)
print("Trying to connect...")
time.sleep(2)
print("Connected.")
print("Waiting to recieve...")
while 1:
buffer = reciever_dongle.rx_buffer.decode("utf-8", "ignore")
if "\r\nhandle_evt_gattc_notification:" in buffer:
save_msg(buffer)
time.sleep(0.5)
except KeyboardInterrupt:
reciever_dongle.at_cancel_connect()
reciever_dongle.at_gapdisconnect()
reciever_dongle.at_advstop()
print("Shutting down script.")
repeater_example_repeter_dongle.py
import time
from bleuio_lib.bleuio_funcs import BleuIo
repeter_dongle_port = "COM38" # Change this to your dongle's COM port
repeter_dongle = BleuIo(port=repeter_dongle_port)
repeter_dongle.start_daemon()
buffer = ""
num_of_connected_devices = 0
connection_list = []
print("Dongle found.")
repeter_dongle.at_dual()
repeter_dongle.at_advstart()
repeter_dongle.rx_state = "rx_waiting"
print("Waiting for other dongles to connect...")
def send_msg(buffer):
"""
Parses incomming data string for just the data and sends it forward via the Serial Port Service.
"""
try:
result = buffer
msg_to_send = ""
result_array1 = result.split("\r\n")
for line in result_array1:
if "[Received]:" in line:
msg_to_send = line.split(" ")
msg_to_send = msg_to_send[1]
break
print("Forwarding data to reciever:")
print(msg_to_send)
if not msg_to_send == "":
repeter_dongle.at_spssend(msg_to_send)
repeter_dongle.rx_state = "rx_waiting"
except:
print(" ")
try:
while 1:
buffer = repeter_dongle.rx_buffer.decode("utf-8", "ignore")
if "\r\nCONNECTED." in buffer:
num_of_connected_devices = num_of_connected_devices + 1
print("A Dongle has connected!")
repeter_dongle.at_advstart()
repeter_dongle.rx_state = "rx_waiting"
if "DISCONNECTED." in buffer:
num_of_connected_devices = num_of_connected_devices - 1
connection_list = []
print("No Dongles connected.")
if num_of_connected_devices > 1:
if "\r\n[Received]:" in buffer:
# print(buffer)
send_msg(buffer)
buffer = ""
time.sleep(0.1)
except KeyboardInterrupt:
repeter_dongle.at_advstop()
repeter_dongle.at_gapdisconnect()
print("Shutting down script.")
repeater_example_sender_dongle.py
import time
from bleuio_lib.bleuio_funcs import BleuIo
import random
sender_dongle_port = "COM73" # Change this to your dongle's COM port
mac_addr_to_repeater = (
"[0]40:48:FD:E5:2D:74" # Change this to your repeater dongle's mac address
)
sender_dongle = BleuIo(port=sender_dongle_port)
sender_dongle.start_daemon()
connected = False
data = ""
buffer = ""
def scan_and_get_results():
"""
Starts a BLE scan for three seconds, looking for results including the 'FF' flag in the advertising data.
Then it saves the results in a list and returns one of the results as a string.
:return: string
"""
print("Scanning...")
return_data = ""
result_list = []
time.sleep(0.5)
try:
scanning = sender_dongle.at_findscandata("FF")
if "SCANNING" in scanning[0]:
time.sleep(4)
sender_dongle.stop_scan()
time.sleep(0.5)
result_list = sender_dongle.rx_scanning_results
if not result_list == []:
if len(result_list) > 3:
lines = result_list[2].split("\r\n")
if not lines[1] == "":
data_array = lines[1].split(" ")
lenght = len(data_array)
if lenght == 5:
data = data_array[4]
return_data = data
else:
sender_dongle.stop_scan()
result_list = []
sender_dongle.rx_state = "rx_waiting"
return_data = ""
except:
sender_dongle.stop_scan()
result_list = []
sender_dongle.rx_state = "rx_waiting"
return_data = ""
return return_data
print("Dongle found.")
try:
sender_dongle.at_dual()
ready = input(
"Press enter to connect to the repeater dongle. (This should be connected last)."
)
print("Connecting...")
sender_dongle.at_gapconnect(mac_addr_to_repeater)
time.sleep(5)
while not connected:
connected_status = sender_dongle.ati()
if "\r\nConnected" in connected_status[0]:
connected = True
break
if "\r\nNot Connected" in connected_status[0]:
sender_dongle.at_gapconnect(mac_addr_to_repeater)
time.sleep(5)
print("Trying to connect...")
time.sleep(2)
print("Connected.")
print("Getting services...")
get_services = sender_dongle.at_get_services()
sender_dongle.rx_state = "rx_waiting"
time.sleep(2)
ready = input("Press enter to start sending data to the repeater dongle.")
while 1:
data = scan_and_get_results()
time.sleep(1)
if not data == "":
sent = sender_dongle.at_spssend(data)
time.sleep(0.1)
if len(sent) == 1:
if "[Sent]" in sent[0]:
print("Data = (" + data + ") sent.")
time.sleep(1)
data = ""
time.sleep(1)
sender_dongle.rx_state = "rx_waiting"
except KeyboardInterrupt:
sender_dongle.at_gapdisconnect()
print("Shutting down script.")
Step 2: Connect two dongles on your PC. You can do the process on three different PC or Raspberry Pi. For this project, I have connected both the sender and receiver dongles to one PC. After connecting the dongles, open device manager (windows) to find ports of each dongle.
On my PC, I have two dongles connected on port 5 and 6. Let’s make COM 5 as the sender, COM 6 as a receiver. Now open the scripts and set the ports number accordingly.
We also need to know repeater dongles ID. To do that, we can simply advertise the dongle on Raspberry pi using AT+ADVSTART command .Then do a gapscan using AT+GAPSCAN from sender dongle and look for a dongle called BleuIO
Once we have repeater dongles id, we can put it on our scripts.
Step 3 :
Now lets run the script.
First move to the script directory on Raspberry pi and using command prompt type sudo python3 repeater_example_repeter_dongle.py to run repeater script.
Similarly, run receiver and sender scripts accordingly on PC.
As the name suggests, the repeater will repeat its content. On the terminal, we will see the message sent to the repeater from the sender, and the repeater forwards the data to the receiver dongle.