B4J Question blue serial port number

Sergio83

Active Member
Licensed User
Longtime User
Hello everybody!

How can I programmatically find the Bluetooth serial port number of the pc where my b4j app is running?

Thanks by advance for your help ...
 

Sergio83

Active Member
Licensed User
Longtime User
what you're proposing me involve the user intervention, is it possible to do that in a transparent manner
 
Upvote 0

Sergio83

Active Member
Licensed User
Longtime User
May be I made a wrong reading, but to get the port name it must be open. So open the port means we already know its name ...
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
[Gemini - I haven't tested it]

On B4J (which runs on Java), the main problem is that standard serial libraries (like the jSerialor library jSerialComm) are able to return the list of all active COM ports on the PC (e.g. COM1, COM3, COM5), but they do not natively specify which of these is associated with a Bluetooth device.

To brilliantly solve the issue on Windows systems (the most common scenario for this type of needs on PC), the best way is not to rely on complex Bluetooth Java libraries (often obsolete or cumbersome like BlueCove), but rather to use the ShellB4J object to directly query the operating system via PowerShell or WMI ( Win32_SerialPort).

Solution in B4J with PowerShell​

You can run a lightweight PowerShell script that filters serial ports for the word "Bluetooth" (such as "Standard Serial over Bluetooth link" ).

Here is an example of ready-to-use B4J code:
B4X:
Sub Process_Globals
    Private MainForm As Form
    Private sh As Shell
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Main") ' Your potential layout
    MainForm.Show
    
    ' Start searching for the Bluetooth port
    SearchBluetoothPort
End Sub

Sub SearchBluetoothPort
    Dim psCommand As String = "Get-CimInstance Win32_SerialPort | Where-Object { $_.Description -like '*Bluetooth*' } | Select-Object DeviceID, Description"
    
    sh.Initialize("sh", "powershell", Array As String("-Command", psCommand))
    sh.Run(10000) ' 10 seconds timeout
End Sub

Sub sh_ProcessCompleted (Success As Boolean, ExitCode As Int, StdOut As String, StdErr As String)
    If Success And ExitCode = 0 Then
        If StdOut.Trim.Length > 0 Then
            Log("Bluetooth port(s) found:")
            Log(StdOut)
            ' Example: Extract the port (e.g., COM3) to use with jSerial
        Else
            Log("No active Bluetooth serial port found.")
        End If
    Else
        Log("Error executing command: " & StdErr)
    End If
End Sub
 
Last edited:
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
[Gemini - I haven't tested it]

On B4J (which runs on Java), the main problem is that standard serial libraries (like the jSerialor library jSerialComm) are able to return the list of all active COM ports on the PC (e.g. COM1, COM3, COM5), but they do not natively specify which of these is associated with a Bluetooth device.

To brilliantly solve the issue on Windows systems (the most common scenario for this type of needs on PC), the best way is not to rely on complex Bluetooth Java libraries (often obsolete or cumbersome like BlueCove), but rather to use the ShellB4J object to directly query the operating system via PowerShell or WMI ( Win32_SerialPort).

Solution in B4J with PowerShell​

You can run a lightweight PowerShell script that filters serial ports for the word "Bluetooth" (such as "Standard Serial over Bluetooth link" ).

Here is an example of ready-to-use B4J code:
B4X:
Sub Process_Globals
    Private MainForm As Form
    Private sh As Shell
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Main") ' Your potential layout
    MainForm.Show
  
    ' Start searching for the Bluetooth port
    SearchBluetoothPort
End Sub

Sub SearchBluetoothPort
    Dim psCommand As String = "Get-CimInstance Win32_SerialPort | Where-Object { $_.Description -like '*Bluetooth*' } | Select-Object DeviceID, Description"
  
    sh.Initialize("sh", "powershell", Array As String("-Command", psCommand))
    sh.Run(10000) ' 10 seconds timeout
End Sub

Sub sh_ProcessCompleted (Success As Boolean, ExitCode As Int, StdOut As String, StdErr As String)
    If Success And ExitCode = 0 Then
        If StdOut.Trim.Length > 0 Then
            Log("Bluetooth port(s) found:")
            Log(StdOut)
            ' Example: Extract the port (e.g., COM3) to use with jSerial
        Else
            Log("No active Bluetooth serial port found.")
        End If
    Else
        Log("Error executing command: " & StdErr)
    End If
End Sub

I dug a little deeper and asked a follow-up question, to which Gemini replied:

The short answer is: yes, for most practical use cases, but with an important distinction.

It depends on what the forum user exactly means by "already open and connected":

1. If they mean: "What is the COM port assigned to my paired Bluetooth device?"​

Yes, the code is sufficient. On Windows, when you pair a Bluetooth serial device (like an HC-05 module, a barcode scanner, or industrial hardware), the operating system creates a dedicated virtual COM port (usually labeled as "Standard Serial over Bluetooth link"). That PowerShell command queries WMI/CIM and returns the exact list of those ports along with their description, allowing the B4J app to immediately identify, for example, that COM5 is the one associated with Bluetooth.

2. If they mean: "I want to know if the Bluetooth device is actually powered on and connected at this precise millisecond"​

It might not be enough. Windows tends to keep virtual Bluetooth COM ports visible and mapped even when the device is powered off or out of range. Consequently, querying Win32_SerialPort tells you which port is configured for Bluetooth, but it does not 100% guarantee that the remote device is actively communicating or online at that moment.

How do developers usually solve this in B4J?​

Often, developers working with Bluetooth serial devices in B4J use a two-step approach:

  1. Use a script similar to the one provided to filter for ports marked as Bluetooth (narrowing down the field and avoiding scans across all PC COM ports, including physical ones).
  2. Attempt the actual connection via the jSerial library on that specific found port, handling any errors if the device happens to be turned off or unreachable.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
I got a script shell error: timeout ?
Yes, it happens to me too.

This version works well:
B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView

    Private sh As Shell
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show

    ' Start searching for the Bluetooth port
    SearchBluetoothPort
End Sub

Sub Button1_Click
    xui.MsgboxAsync("Hello World!", "B4X")
End Sub

Sub SearchBluetoothPort
    ' We use the PowerShell pipeline without complex WQL queries: filtering PnP objects directly.
    Dim psCommand As String = "Get-WmiObject Win32_PnPEntity | Where-Object { $_.Name -like '*Bluetooth*' } | Select-Object DeviceID, Name"
  
    sh.InitializeDoNotHandleQuotes("sh", "powershell", Array As String("-Command", psCommand))
    sh.Run(10000)
End Sub

Sub sh_ProcessCompleted (Success As Boolean, ExitCode As Int, StdOut As String, StdErr As String)
    If Success And ExitCode = 0 Then
        If StdOut.Trim.Length > 0 Then
            Log("Bluetooth port(s) found:")
            Log(StdOut)
            ' Example: Extract the port (e.g., COM3) to use with jSerial
        Else
            Log("No active Bluetooth serial port found.")
        End If
    Else
        Log("Error executing command: " & StdErr)
    End If
End Sub

Log:
Waiting for debugger to connect...
Program started.
Bluetooth port(s) found:
DeviceID Name
-------- ----
BTH\MS_BTHBRB\7&2E011D8A&0&1 Enumeratore Bluetooth Microsoft
BTHENUM\{00001132-0000-1000-8000-008... Dispositivo Bluetooth
BTH\MS_BTHPAN\7&2E011D8A&0&2 Dispositivo Bluetooth (Personal Area...
BTHENUM\{0000FE35-0000-1000-8000-008... Dispositivo Bluetooth
BTH\MS_RFCOMM\7&2E011D8A&0&0 Dispositivo Bluetooth (RFCOMM protoc...
BTHENUM\{0000046A-0000-1000-8000-008... Dispositivo Bluetooth
ROOT\AMPPAL\0000 Scheda virtuale Intel� Centrino� Wir...
BTHENUM\{747413E4-F767-414F-A0C1-6CC... Bluetooth Audio
BTHENUM\{00001103-0000-1000-8000-008... Modem standard su collegamento Bluet...
BTHENUM\{00001800-0000-1000-8000-008... Dispositivo Bluetooth
BTHENUM\{F0B2DD71-FB14-4E30-A62D-931... Bluetooth Server
BTHENUM\{00001800-0000-1000-8000-008... Dispositivo Bluetooth
USB\VID_8086&PID_0189\6&32F586E2&0&3 Intel(R) Centrino(R) Wireless Blueto...
BTHENUM\{00001801-0000-1000-8000-008... Dispositivo Bluetooth
 
Upvote 0

Sergio83

Active Member
Licensed User
Longtime User
ok LucaMs, your appli runs ok on my pc, I've checked line by line your code and mine, no difference, but in the log of your appli there not characteres string like "COM5" it is what I try to get! Anyway, thank you a lot to have spent time to try to help me!
 
Upvote 0

Chris2

Well-Known Member
Licensed User
Longtime User
May be I made a wrong reading, but to get the port name it must be open. So open the port means we already know its name ...
With jSerial Enhanced Library:
B4X:
Private Serial As jSerialEnhanced
Log(Serial.ListPorts)
 
    For Each port As String In Serial.ListPorts
        Dim PortInfo As Map = Serial.GetPortInfo(port)

        Log("Port Name: " & PortInfo.Get("PortName"))
        Log("Port Description: " & PortInfo.Get("PortDescription"))
        Log("Descriptive Port: " & PortInfo.Get("DescriptivePort"))
        Log("VID: " & PortInfo.Get("VID"))
        Log("PID: " & PortInfo.Get("PID"))
        Log("Manufacturer: " & PortInfo.Get("Manufacturer"))
        Log("Serial Number: " & PortInfo.Get("SerialNumber"))
        Log("Product: " & PortInfo.Get("Product"))
    Next

Gives me:
(ArrayList) [COM1, COM3]
Port Name: COM1
Port Description: Communications Port (COM1)
Descriptive Port: Communications Port (COM1)
VID: -1
PID: -1
Manufacturer: (Standard port types)
Serial Number: Unknown
Product: null
Port Name: COM3
Port Description: US232R
Descriptive Port: USB Serial Port (COM3)
VID: 1027
PID: 24577
Manufacturer: FTDI
Serial Number: FTU93OAW
Product: null
I didn't need to open the ports.
[I don't have a bluetooth serial port but I imagine that yours will show up in the 'DescriptivePort' line]
 
Last edited:
Upvote 0

Chris2

Well-Known Member
Licensed User
Longtime User
it seems not ...
So what do you get?
Can you identify the bluetooth port by the manufacturer or with whatever you get from jSerialEnhanced.GetDeviceType?
It might not be perfect, but maybe you could look in info provided by jSerialEnhanced.GetPortInfo for one of a list of known bluetooth to serial chipset manufacturers?
For example, FTDI are a well known producer of USB adaptors, so seeing that in a list of comms ports I could identify it as a USB adaptor.
 
Upvote 0

Sergio83

Active Member
Licensed User
Longtime User
I found that piece of code:

B4X:
Public Sub DetecterPortBluetooth
    ' Commande PowerShell pour lister les ports COM avec leur description
    Dim Query As String = "Get-CimInstance Win32_SerialPort | Select-Object DeviceID, Name | Format-Table -HideTableHeaders"
    
    sh.Initialize("powershell", "powershell.exe", Array As String("-NoProfile", "-Command", Query))
    sh.Run(-1) ' -1 pour aucun timeout
End Sub

Private Sub powershell_ProcessCompleted (Success As Boolean, ExitCode As Int, StdOut As String, StdErr As String)
    If Success And ExitCode = 0 Then
        ' Analyse de la chaîne reçue
        Dim Lines() As String = Regex.Split(CRLF, StdOut)
        For Each Line As String In Lines
            Line = Line.Trim
            ' Utilisation correcte de .ToLowerCase en B4X
            If Line.ToLowerCase.Contains("bluetooth") Then
                Dim Matcher1 As Matcher = Regex.Matcher("COM\d+", Line)
                If Matcher1.Find Then
                    Dim PortTrouve As String = Matcher1.Match
                    Log("Port Bluetooth détecté avec succès : " & PortTrouve)
                    Return
                End If
            End If
        Next
        Log("Aucun port série Bluetooth trouvé dans le système.")
    Else
        Log("Erreur lors de l'exécution du Shell : " & StdErr)
    End If
End Sub

with in process global:

B4X:
Private sh As Shell

and in appstart:

B4X:
DetecterPortBluetooth

log result is:

Port Bluetooth détecté avec succès : COM5Port Bluetooth détecté avec succès : COM5:
Port Bluetooth détecté avec succès : COM5

Sorry for the language but I'm french.

If it could help anybody ...
 
Upvote 0
Top