Get Bluetooth Device Distance in meter Using Javascript

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.

Read more about how to calculate the distance

How to Calculate Distance from the RSSI value of the BLE Beacon

Requirments

Instructions

git clone https://github.com/smart-sensor-devices-ab/ble_distance_measure.git

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.

Here is the index.html file

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">

    <title>Get Device Distance Using BleuIO</title>
  </head>
  <body>
    <div class="container"> <br>
    <a href="https://www.bleuio.com/"> <img src="https://www.bleuio.com/images/logo.png" alt="BleuIO get device distance"></a>
    <h1>Get Device Distance Using BleuIO</h1>
<br>
    <button id="connect" class="btn btn-success">Connect</button>
<button id="scan" class="btn btn-warning">Scan Devices</button> &nbsp; &nbsp;  <span id="scanning" class="d-none"> scanning ...</span>  <br><br><br>
<div id="deviceList"></div>
</div>
<br><br>
<script src="./script.js"></script>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>


  </body>
</html>

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.

You can also run this script from online at
https://smart-sensor-devices-ab.github.io/ble_distance_measure/dist/

**Make sure your BleuIO dongle is connected

Output

Share this post on :

Transfer files wirelessly over the Bluetooth Low Energy protocol Using Python

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 

https://github.com/smart-sensor-devices-ab/bleuio_file_transfer_example

You can try this project on two different computers.

A video tutorial will show you how to do it on one computer and send files between two BleuIO dongles.

Requirements :

Steps:

  • 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. 

Share this post on :

Bleuio Firmware Update V2.0.5

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

Share this post on :