How to get information about a connected/paired Bluetooth device in Java?
Asked Answered
Q

1

8

I'm a beginner with Bluetooth. I'm trying to use Bluecove with Java. I would like to communicate with a device which is already connected/paired to my computer (such as retrieving device battery levels). The problem is that I can't find the connected device.

I know I can have the local device, retrieve devices etc, but I can't have the connected device. I'm using the code found here.

I am ready to try another library if needed.

In BluetoothDevices.java :

import javax.swing.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BluetoothDevices extends javax.swing.JFrame {

    /* DefaultListModel to attach it with JList */
    private DefaultListModel defaultModel;
    /* Map to get device details list */
    private Map<String, List<String>> mapReturnResult = new HashMap<String, List<String>>();
    /* Map to identify device on user click of JList */
    private Map<Integer, List<String>> mapDevicePosition = new HashMap<Integer, List<String>>();

    public BluetoothDevices() {
        initComponents();
        defaultModel = new DefaultListModel();
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        JListBluetoothDevices = new javax.swing.JList();
        lblDeviceName = new javax.swing.JLabel();
        lblRuntimeDeviceName = new javax.swing.JLabel();
        lblDeviceAddress = new javax.swing.JLabel();
        lblRuntimeDeviceAddress = new javax.swing.JLabel();
        lblServiceDetails = new javax.swing.JLabel();
        jScrollPane2 = new javax.swing.JScrollPane();
        JTextAreaServiceDetails = new javax.swing.JTextArea();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Bluecove Bluetooth Discovery");
        setResizable(false);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowOpened(java.awt.event.WindowEvent evt) {
                formWindowOpened(evt);
            }
        });

        JListBluetoothDevices.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                JListBluetoothDevicesMouseClicked(evt);
            }
        });
        jScrollPane1.setViewportView(JListBluetoothDevices);

        lblDeviceName.setText("Bluetooth Device Name");

        lblDeviceAddress.setText("Bluetooth Device Address");

        lblServiceDetails.setText("Service Details");

        JTextAreaServiceDetails.setColumns(20);
        JTextAreaServiceDetails.setRows(5);
        jScrollPane2.setViewportView(JTextAreaServiceDetails);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                                .addContainerGap()
                                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 158, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addGroup(layout.createSequentialGroup()
                                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                                        .addComponent(lblDeviceName)
                                                        .addComponent(lblDeviceAddress))
                                                .addGap(73, 73, 73)
                                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                                        .addComponent(lblRuntimeDeviceAddress)
                                                        .addComponent(lblRuntimeDeviceName, javax.swing.GroupLayout.PREFERRED_SIZE, 144, javax.swing.GroupLayout.PREFERRED_SIZE)))
                                        .addComponent(lblServiceDetails)
                                        .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 475, Short.MAX_VALUE))
                                .addContainerGap())
        );
        layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                                .addContainerGap()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 185, Short.MAX_VALUE)
                                        .addGroup(layout.createSequentialGroup()
                                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                                        .addComponent(lblDeviceName)
                                                        .addComponent(lblRuntimeDeviceName))
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                                        .addComponent(lblDeviceAddress)
                                                        .addComponent(lblRuntimeDeviceAddress))
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                                .addComponent(lblServiceDetails)
                                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                                .addComponent(jScrollPane2, 0, 0, Short.MAX_VALUE)))
                                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    /* Search for bluetooth device when window opened */
    private void formWindowOpened(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowOpened
        int intDevicePosition = 0;
        JListBluetoothDevices.setModel(defaultModel);

        /* Create an object of ServicesSearch */
        ServicesSearch ss = new ServicesSearch();
        /* Get bluetooth device details */
        mapReturnResult = ss.getBluetoothDevices();

        /* Add devices in JList */
        for (Map.Entry<String, List<String>> entry : mapReturnResult.entrySet()) {
            defaultModel.addElement(entry.getValue().get(0));
            mapDevicePosition.put(intDevicePosition, entry.getValue());
            intDevicePosition++;
        }
    }//GEN-LAST:event_formWindowOpened

    /* On click of any item in List Box */
    private void JListBluetoothDevicesMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_JListBluetoothDevicesMouseClicked
  /* Get bluetooth device details from temporary list */
        List<String> tmpDeviceDetails = mapDevicePosition.get(JListBluetoothDevices.getSelectedIndex());
  /* Set bluetooth device name */
        lblRuntimeDeviceName.setText(tmpDeviceDetails.get(0));
  /* Set bluetooth device Address */
        lblRuntimeDeviceAddress.setText(tmpDeviceDetails.get(1));

        if (tmpDeviceDetails.size() > 2 && tmpDeviceDetails.get(2) != null) {
   /* Set bluetooth device service name and URL */
            JTextAreaServiceDetails.setText(tmpDeviceDetails.get(2));
        } else {
            JTextAreaServiceDetails.setText("Service not found");
        }
    }//GEN-LAST:event_JListBluetoothDevicesMouseClicked

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                 /* To set new look and feel */
                JFrame.setDefaultLookAndFeelDecorated(true);
                try {
                    /**
                     * Change look and feel of JFrame to Nimbus
                     * For other look and feel check
                     * http://www.javaquery.com/2013/06/how-to-applyset-up-swing-look-and-feel.html
                     */
                    UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                /* Create an object of BluetoothDevices */
                BluetoothDevices bluetoothDevicesFrame = new BluetoothDevices();
                /* make BluetoothDevices visible */
                bluetoothDevicesFrame.setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JList JListBluetoothDevices;
    private javax.swing.JTextArea JTextAreaServiceDetails;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JLabel lblDeviceAddress;
    private javax.swing.JLabel lblDeviceName;
    private javax.swing.JLabel lblRuntimeDeviceAddress;
    private javax.swing.JLabel lblRuntimeDeviceName;
    private javax.swing.JLabel lblServiceDetails;
    // End of variables declaration//GEN-END:variables
}

In ServicesSearch.java :

import javax.bluetooth.*;
import javax.bluetooth.UUID;
import java.util.*;

public class ServicesSearch {

    /**
     * UUID used to find specific service supported by bluetooth device
     * https://www.bluetooth.org/en-us/specification/assigned-numbers/service-discovery
     * Find UUIDs for all types of bluetooth services.
     */
    /* To find push object service */
    private UUID OBEX_OBJECT_PUSH_PROFILE = new UUID(0x1105);
    /* To find file transfer service */
    private UUID OBEX_FILE_TRANSFER_PROFILE = new UUID(0x1106);
    /* To find hands free service */
    private UUID HANDS_FREE = new UUID(0x111E);
    /* Get URL attribute from bluetooth service */
    private int URL_ATTRIBUTE = 0X0100;

    public Map<String, List<String>> getBluetoothDevices() {
        /**
         * Find service on bluetooth device
         * Note: In following line you can use one service at a time. I'm new to bluetooth programming it might me wrong perception.
         * UUID[] searchUuidSet = new UUID[]{OBEX_FILE_TRANSGER_PROFILE};
         *
         * CORRECT: UUID[] searchUuidSet = new UUID[]{OBEX_FILE_TRANSGER_PROFILE};
         * WRONG: UUID[] searchUuidSet = new UUID[]{OBEX_FILE_TRANSGER_PROFILE, OBEX_OBJECT_PUSH_PROFILE};
         */
        /* Initialize UUID Array */
        UUID[] searchUuidSet = new UUID[]{HANDS_FREE};
        final Object serviceSearchCompletedEvent = new Object();
        int[] attrIDs = new int[]{URL_ATTRIBUTE};

        /* Create an object to get list of devices in range or paired */
        RemoteDeviceDiscovery remoteDeviceDiscovery = new RemoteDeviceDiscovery();
        /* Create map to return Bluetooth device address, name and URL */
        final Map<String, List<String>> mapReturnResult = new HashMap<String, List<String>>();

        try {
            /* Create an object of DiscoveryListener */
            DiscoveryListener listener = new DiscoveryListener() {

                /* To find bluetooth devices */
                public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
                }

                /* To find bluetooth devices */
                public void inquiryCompleted(int discType) {
                }

                /* Find service URL of bluetooth device */
                public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
                    for (int i = 0; i < servRecord.length; i++) {
                        /* Find URL of bluetooth device */
                        String url = servRecord[i].getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
                        if (url == null) {
                            continue;
                        }
                        String temporaryString = "";
                        /* Get object of bluetooth device */
                        RemoteDevice rd = servRecord[i].getHostDevice();
                        /* Get attribute from ServiceRecord */
                        DataElement serviceName = servRecord[i].getAttributeValue(URL_ATTRIBUTE);
                        if (serviceName != null) {
                            temporaryString = serviceName.getValue() + "\n" + url;
                            /* Put it in map */
                            mapReturnResult.get(rd.getBluetoothAddress()).add(temporaryString);
                        } else {
                            temporaryString = "Uknown service \n" + url;
                            /* Put it in map */
                            mapReturnResult.get(rd.getBluetoothAddress()).add(temporaryString);
                        }
                    }
                }

                public void serviceSearchCompleted(int transID, int respCode) {
                    /* Notify thread when search completed */
                    synchronized (serviceSearchCompletedEvent) {
                        serviceSearchCompletedEvent.notifyAll();
                    }
                }
            };

            /* Get list of bluetooth device from class RemoteDeviceDiscovery */
            for (Enumeration en = remoteDeviceDiscovery.getDevices().elements(); en.hasMoreElements();) {
                /* Get RemoteDevice object */
                RemoteDevice btDevice = (RemoteDevice) en.nextElement();
                /* Create list to return details */
                List<String> listDeviceDetails = new ArrayList<String>();

                try {
                    /* Add bluetooth device name and address in list */
                    listDeviceDetails.add(btDevice.getFriendlyName(false));
                    listDeviceDetails.add(btDevice.getBluetoothAddress());
                } catch (Exception e) {
                }

                /* Put bluetooth device details in map */
                mapReturnResult.put(btDevice.getBluetoothAddress(), listDeviceDetails);
                synchronized (serviceSearchCompletedEvent) {
                    LocalDevice.getLocalDevice().getDiscoveryAgent().searchServices(attrIDs, searchUuidSet, btDevice, listener);
                    serviceSearchCompletedEvent.wait();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        /* Return bluetooth devices detail */
        return mapReturnResult;
    }
}

In RemoteDeviceDiscovery.java :

import javax.bluetooth.*;
import java.io.IOException;
import java.util.Vector;

public class RemoteDeviceDiscovery {

    public Vector getDevices() {
        /* Create Vector variable */
        final Vector devicesDiscovered = new Vector();
        try {
            final Object inquiryCompletedEvent = new Object();
            /* Clear Vector variable */
            devicesDiscovered.clear();

            LocalDevice device = LocalDevice.getLocalDevice();

            System.out.println("Address : " + device.getBluetoothAddress());
            System.out.println("Name : " + device.getFriendlyName());
            System.out.println("Powered : " + device.isPowerOn());

            RemoteDevice[] devices = device.getDiscoveryAgent().retrieveDevices(DiscoveryAgent.PREKNOWN);

            for (RemoteDevice d : devices) {
                System.out.println("Adress : " + d.getBluetoothAddress());
                System.out.println("Name : " + d.getFriendlyName(false));
                System.out.println("Authenticated : " + d.isAuthenticated());
                System.out.println("Trusted : " + d.isTrustedDevice());
                System.out.println();
            }

            /* Create an object of DiscoveryListener */
            DiscoveryListener listener = new DiscoveryListener() {

                public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
                    /* Get devices paired with system or in range(Without Pair) */
                    System.out.println("Address : " + btDevice.getBluetoothAddress());
                    try {
                        System.out.println("Name : " + btDevice.getFriendlyName(false));
                    } catch (IOException e) {
                    }
                    devicesDiscovered.addElement(btDevice);
                }

                public void inquiryCompleted(int discType) {
                    /* Notify thread when inquiry completed */
                    synchronized (inquiryCompletedEvent) {
                        inquiryCompletedEvent.notifyAll();
                    }
                }

                /* To find service on bluetooth */
                public void serviceSearchCompleted(int transID, int respCode) {
                }

                /* To find service on bluetooth */
                public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
                }
            };

            synchronized (inquiryCompletedEvent) {
                /* Start device discovery */
                boolean started = LocalDevice.getLocalDevice().getDiscoveryAgent().startInquiry(DiscoveryAgent.GIAC, listener);
                if (started) {
                    System.out.println("wait for device inquiry to complete...");
                    inquiryCompletedEvent.wait();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        /* Return list of devices */
        return devicesDiscovered;
    }
}

As you can see, I tried to get the all PREKNOWN devices for LocalDevice. Here, I can find every Bluetooth devices I have already connected to my computer but I can't know if it is connected.

Here is the output :

Address : 000000000003
Name : M
Powered : true

Adress : ACD1B8925628
Name : BLU-RAY HOME THEATRE SYSTEM
Authenticated : false
Trusted : false

Adress : A0143D6B170A
Name : Parrot ZIK 2.0 V2.05
Authenticated : false
Trusted : false

Adress : DC415F7780BB
Name : iPhone de Benjamin
Authenticated : false
Trusted : false

Adress : B0B28FD3668D
Name : LaBox6687
Authenticated : false
Trusted : false

wait for device inquiry to complete...
Address : 4D08B6DE2FDE
Name : LaBox6687
Address : A5362CC20702

The device I want to use is Parrot ZIK 2.0 V2.05.

Quirk answered 18/12, 2016 at 0:22 Comment(12)
May we see what code/config you have at present?Henninger
That's great, thank you. I don't have the knowledge to help on this one, but someone should be able to assist now. For bonus points, can you show what output is rendered to stdout when you run this, or are there Bluetooth logs that would help a reader pinpoint your problem?Henninger
Here is the output. Thank you!Quirk
I don't know BT all that well, but could it be a BT version issue? My old phone would not pair with a much newer fitness bracelet, since the bracelet seemed to be using BT Low Energy, or maybe BT4, and my phone only implemented a much earlier option.Henninger
How do you know? Please give as much detail in any comment you give here, so as to reduce the necessary rounds of conversation.Henninger
*It's not a pairing problem. The device is paired to the computer. All I want is to intercept the connection to retrieve some data (Battery level, etc).Quirk
Let us continue this discussion in chat.Quirk
github.com/movisens/SmartGattLib This library seems to claim that it can get details like battery level.Constantinople
I'll try it, thank you!Quirk
@Delaco: please let Rajind know if this works, so he/she can benefit from the bounty before it expires. Thanks.Henninger
@Henninger added the answer. To be frank I haven't got the time to try it out yet.Constantinople
Thanks @Rajind! I am sure Delaco will let us know how they get on with it.Henninger
C
5

In the linked library docs they claim the following:

SmartGattLib is a Java library that simplifies the work with Bluetooth SMART devices (a.k.a. Bluetooth Low Energy in Bluetooth 4.0). It provides all UUIDs of the adopted GATT specification and an convenient way to interpret the characteristics (e.g. Heart Rate, BatteryLevel).

Implemented and tested characteristics

  • BatteryLevel
  • BodySensorLocation
  • HeartRateMeasurement
  • ManufacturerNameString

Hope these two examples in test classes will help too.

Constantinople answered 24/12, 2016 at 13:11 Comment(1)
Thank you @Rajind, I haven't got time to test for now (school projects you know...) but I'll try in a few week!Quirk

© 2022 - 2024 — McMap. All rights reserved.