Saturday, June 6, 2026

Java: using thermal printer 6106 - 80mm esc/pos java in debian 13 bluetooth

Install bluetooth software


$ apt install firmware-misc-nonfree bluez bluez-tools blueman screen

linux user groups: bluetooth, lp, netdev, sudo, and plugdev

add linux user to group


# usermod -aG sudo username

check your bluetooth adapter has been recognize by debian


$ lsusb
...
Bus 001 Device 003: ID 0489:e0cd Foxconn / Hon Hai MediaTek Bluetooth Adapter
...

pair your device, if you don't hook it in boot, you need to rebind after boot. 


$ bluetoothctl pair 86:67:7A:1D:C2:E3
Attempting to pair with 86:67:7A:1D:C2:E3
[CHG] Device 86:67:7A:1D:C2:E3 Connected: yes
Failed to pair: org.bluez.Error.AuthenticationFailed

using bluetoothctl to handle bluetooth password


$ bluetoothctl
Agent registered
[bluetoothctl]> agent KeyboardOnly
Agent is already registered
[bluetoothctl]> default-agent
Default agent request successful
[bluetoothctl]> scan on
SetDiscoveryFilter success
Discovery started
[CHG] Controller BC:F4:D4:12:4C:28 Discovering: yes
[NEW] Device 4D:F9:CE:48:C4:1B 4D-F9-CE-48-C4-1B
[NEW] Device 62:FE:E1:08:CD:73 62-FE-E1-08-CD-73
[NEW] Device 6D:AC:09:7B:A7:F3 6D-AC-09-7B-A7-F3
[NEW] Device 86:67:7A:1D:C2:E3 RPP02N
[bluetoothctl]> pair 86:67:7A:1D:C2:E3
Attempting to pair with 86:67:7A:1D:C2:E3
[CHG] Device 86:67:7A:1D:C2:E3 Connected: yes
[CHG] Device 86:67:7A:1D:C2:E3 Bonded: yes
[CHG] Device 86:67:7A:1D:C2:E3 Modalias: usb:v05ACp0239d0644
[CHG] Device 86:67:7A:1D:C2:E3 ServicesResolved: yes
[CHG] Device 86:67:7A:1D:C2:E3 Paired: yes
Pairing successful
[DEL] Device 6D:AC:09:7B:A7:F3 6D-AC-09-7B-A7-F3
[CHG] Device 86:67:7A:1D:C2:E3 ServicesResolved: no
[CHG] Device 86:67:7A:1D:C2:E3 Connected: no
[DEL] Device 4D:F9:CE:48:C4:1B 4D-F9-CE-48-C4-1B
[DEL] Device 62:FE:E1:08:CD:73 62-FE-E1-08-CD-73
[bluetoothctl]> trust 86:67:7A:1D:C2:E3
[CHG] Device 86:67:7A:1D:C2:E3 Trusted: yes
Changing 86:67:7A:1D:C2:E3 trust succeeded

busctl output


$ busctl introspect org.bluez /org/bluez/hci0/dev_86_67_7A_1D_C2_E3
NAME                                TYPE      SIGNATURE RESULT/VALUE                             FLAGS
org.bluez.Device1                   interface -         -                                        -
.CancelPairing                      method    -         -                                        -
.Connect                            method    -         -                                        -
.ConnectProfile                     method    s         -                                        -
.Disconnect                         method    -         -                                        -
.DisconnectProfile                  method    s         -                                        -
.Pair                               method    -         -                                        -
.Adapter                            property  o         "/org/bluez/hci0"                        emits-change
.Address                            property  s         "86:67:7A:1D:C2:E3"                      emits-change
.AddressType                        property  s         "public"                                 emits-change
.AdvertisingData                    property  a{yv}     -                                        emits-change
.AdvertisingFlags                   property  ay        -                                        emits-change
.Alias                              property  s         "RPP02N"                                 emits-change writable
.Appearance                         property  q         -                                        emits-change
.Blocked                            property  b         false                                    emits-change writable
.Bonded                             property  b         true                                     emits-change
.Class                              property  u         263808                                   emits-change
.Connected                          property  b         false                                    emits-change
.Icon                               property  s         "printer"                                emits-change
.LegacyPairing                      property  b         false                                    emits-change
.ManufacturerData                   property  a{qv}     -                                        emits-change
.Modalias                           property  s         "usb:v05ACp0239d0644"                    emits-change
.Name                               property  s         "RPP02N"                                 emits-change
.Paired                             property  b         true                                     emits-change
.RSSI                               property  n         -                                        emits-change
.ServiceData                        property  a{sv}     -                                        emits-change
.ServicesResolved                   property  b         false                                    emits-change
.Sets                               property  a{oa{sv}} -                                        emits-change
.Trusted                            property  b         true                                     emits-change writable
.TxPower                            property  n         -                                        emits-change
.UUIDs                              property  as        7 "00000001-0000-1000-8000-00805f9b34fb… emits-change
.WakeAllowed                        property  b         -                                        emits-change writable
org.freedesktop.DBus.Introspectable interface -         -                                        -
.Introspect                         method    -         s                                        -
org.freedesktop.DBus.Properties     interface -         -                                        -
.Get                                method    ss        v                                        -
.GetAll                             method    s         a{sv}                                    -
.Set                                method    ssv       -                                        -
.PropertiesChanged                  signal    sa{sv}as  -                                        -

bind to rfcomm (sudo), if you don't hook it in boot, you need to rebind after boot.


  # rfcomm bind rfcomm0 86:67:7A:1D:C2:E3

or with sudo


  $ sudo  rfcomm bind rfcomm0 86:67:7A:1D:C2:E3

your dev access point


$ ls /dev/ | grep rfcomm
rfcomm0

get your bluetooth device info


$ bluetoothctl info 86:67:7A:1D:C2:E3
Device 86:67:7A:1D:C2:E3 (public)
	Name: RPP02N
	Alias: RPP02N
	Class: 0x00040680 (263808)
	Icon: printer
	Paired: yes
	Bonded: yes
	Trusted: yes
	Blocked: no
	Connected: no
	LegacyPairing: no
	UUID: SDP                       (00000001-0000-1000-8000-00805f9b34fb)
	UUID: RFCOMM                    (00000003-0000-1000-8000-00805f9b34fb)
	UUID: L2CAP                     (00000100-0000-1000-8000-00805f9b34fb)
	UUID: Serial Port               (00001101-0000-1000-8000-00805f9b34fb)
	UUID: PnP Information           (00001200-0000-1000-8000-00805f9b34fb)
	UUID: Unknown                   (000018f0-0000-1000-8000-00805f9b34fb)
	UUID: Vendor specific           (e7810a71-73ae-499d-8c15-faa9aef0c3f2)
	Modalias: usb:v05ACp0239d0644

Optional: to let systemd handling pair device

create/edit bluetooth-printer.service (or any name you wish), at /etc/systemd/system/, e.g   /etc/systemd/system/bluetooth-printer.service.


[Unit]
Description=Bind Bluetooth Thermal Printer to rfcomm0
After=bluetooth.service
Requires=bluetooth.service

[Service]
Type=oneshot
ExecStart=/usr/bin/rfcomm bind rfcomm0 86:67:7A:1D:C2:E3
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

After that use systemd to handle pairing

  • sudo systemctl daemon-reload
  • sudo systemctl enable bluetooth-printer.service
  • sudo systemctl start bluetooth-printer.service
  • systemctl status bluetooth-printer.service 

you can try previous code https://dedetoknotes.blogspot.com/2026/06/java-using-thermal-printer-6106-80mm.html by change 

devicePath = "/dev/usb/lp1" 

to

devicePath = "/dev/rfcomm0" 

Credit: https://www.freeformatter.com/html-escape.html#before-output to esc html 

Monday, June 1, 2026

Java: using thermal printer 6106 - 80mm esc/pos java in debian 13 usb

insert your printer using usb cable


# lsusb
...
Bus 008 Device 002: ID 28e9:0289 GDMicroelectronics micro-printer
Bus 009 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
# dmesg
[   70.532011] usb 8-1: new full-speed USB device number 2 using xhci_hcd
[   70.688254] usb 8-1: New USB device found, idVendor=28e9, idProduct=0289, bcdDevice= 2.00
[   70.688270] usb 8-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[   70.688276] usb 8-1: Product: micro-printer
[   70.688282] usb 8-1: Manufacturer: GEZHI
[   70.688286] usb 8-1: SerialNumber: 000000000004
[   70.730721] usblp 8-1:1.0: usblp1: USB Bidirectional printer dev 2 if 0 alt 0 proto 2 vid 0x28E9 pid 0x0289
[   70.730783] usbcore: registered new interface driver usblp
use nl80211
# ls -al /dev/usb/
total 0
drwxr-xr-x  2 root root     80 May 31 14:31 .
drwxr-xr-x 20 root root   3840 May 31 14:31 ..
crw-------  1 root root 180, 0 May 31 14:30 hiddev0
crw-rw----  1 root lp   180, 1 May 31 14:31 lp1
# ls -al /dev/usb/lp1
crw-rw---- 1 root lp 180, 1 May 31 14:31 /dev/usb/lp1

we found the device known as usb lp1 i.e. /dev/usb/lp1. test to print something.


# printf '\x1b\x40Hello World\n\n\n' > /dev/usb/lp1

your printer should print "Hello World"

add your account or linux user as lp group 


# usermod -aG lp [username]

you need to sign out and re sign in, then try to print as [username]


$ printf '\x1b\x40Hello World\n\n\n' > /dev/usb/lp1

if everything work, now you can work as [username]. this is simple netbeans 30 - maven, to test your printer.

This is pom.xml for your project.


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.dedetok</groupId>
    <artifactId>EnumComPort</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.release>21</maven.compiler.release>
        <exec.mainClass>com.dedetok.enumcomport.EnumComPort</exec.mainClass>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.fazecast</groupId>
            <artifactId>jSerialComm</artifactId>
            <version>2.11.0</version>
            <type>jar</type>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.5.0</version>

                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>

                        <configuration>
                            <createDependencyReducedPom>false</createDependencyReducedPom>

                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.dedetok.enumcomport.EnumComPort</mainClass>
                                </transformer>
                            </transformers>

                        </configuration>
                    </execution>
                </executions>

            </plugin>

        </plugins>
    </build>
</project>

This is the java code


package com.dedetok.enumcomport;

import com.fazecast.jSerialComm.SerialPort;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 *
 * @author dedetok
 */
public class EnumComPort {

    public static void main(String[] args) throws IOException {
        System.out.println("Hello World!");
        System.out.println(System.getProperty("user.name"));
        Process p = Runtime.getRuntime().exec("id");
        p.getInputStream().transferTo(System.out);
        
        SerialPort[] ports = SerialPort.getCommPorts();

        if (ports.length == 0) {
            System.out.println("No serial ports detected.");
        }

        System.out.println("Available Serial Ports:");
        System.out.println("------------------------");

        for (SerialPort port : ports) {

            System.out.println("System Port Name : " + port.getSystemPortName());
            System.out.println("Descriptive Name: " + port.getDescriptivePortName());
            System.out.println("Port Description: " + port.getPortDescription());
            System.out.println("System Location : " + port.getSystemPortPath());
            System.out.println("------------------------");
        }
        
        String devicePath = "/dev/usb/lp1";
        // Open file in read-write mode for raw bidirectional access
        RandomAccessFile deviceFile = new RandomAccessFile(devicePath, "rw");
        FileDescriptor fd = deviceFile.getFD();
        
        try (OutputStream out = new FileOutputStream(fd)) {
            // ESC @ (initialize)
            out.write(new byte[]{0x1B, 0x40});

            out.write("Hello World\n".getBytes());

            // Feed
            out.write("\n\n".getBytes());

            // Cut
            out.write(new byte[]{0x1D, 0x56, 0x00});

            out.flush();
            out.close(); // NO NEED
        } catch (FileNotFoundException ex) {
            System.getLogger(EnumComPort.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex);
        }
        System.out.println("End");
    }
}

In my test, you can run inside your netbeans, Run -> Build Project or Run -> Clean and Run Project. to run the jar, you go to project root and run like this


$ java -jar ./target/EnumComPort-1.0.jar 
Hello World!
[username]
uid=1000([username]) gid=1000([username]) groups=1000([username]),7(lp),20(dialout),24(cdrom),25(floppy),29(audio),30(dip),33(www-data),44(video),46(plugdev),100(users),106(netdev),111(bluetooth),113(lpadmin),116(scanner),124(libvirt)
No serial ports detected.
Available Serial Ports:
------------------------
End

your print should print "Hello World". "No serial ports" means, you can use com.fazecast.jSerialComm library for lp printer.

Credit: https://www.freeformatter.com/html-escape.html for free html escape 

Saturday, May 30, 2026

Java: enumerate com serial using fazecast jSerialComm

Simple code to enumerate serial com port


/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 */

package com.dedetok.enumcomport;

import com.fazecast.jSerialComm.SerialPort;

/**
 *
 * @author dedetok
 */
public class EnumComPort {

    public static void main(String[] args) {
        System.out.println("Hello World!");

        SerialPort[] ports = SerialPort.getCommPorts();

        if (ports.length == 0) {
            System.out.println("No serial ports detected.");
            return;
        }

        System.out.println("Available Serial Ports:");
        System.out.println("------------------------");

        for (SerialPort port : ports) {

            System.out.println("System Port Name : " + port.getSystemPortName());
            System.out.println("Descriptive Name: " + port.getDescriptivePortName());
            System.out.println("Port Description: " + port.getPortDescription());
            System.out.println("System Location : " + port.getSystemPortPath());
            System.out.println("------------------------");
        }
        
    }
}

Note: lpx device (e.g /dev/usb/lp1) does not use serial com, you need to send hex code direct via OutputStream.

Java: Hook shutdown to run java application as systemd

This is minimum java code to hook shutdown


/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 */

package com.dedetok.javaservicetest;

/**
 *
 * @author dedetok
 */
public class JavaServiceTest {

    private static volatile boolean running = true;
        
    public static void main(String[] args) {
        System.out.println("Hello World!");
        
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("Shutdown hook triggered");

            running = false;

            // Cleanup resources here
            // Close database connections
            // Flush logs
            // Stop worker threads
            // Main shutdown path
            //cleanupResources();

            System.out.println("Cleanup complete");
        }));

        System.out.println("Daemon started");

        while (running) {
            System.out.println("Working...");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException ex) {
                System.getLogger(JavaServiceTest.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex);
            }
        }

    }
}

to run/test this application, you can not run it inside netbeans. use terminal to run it, go to your project root and run


$ java -cp target/classes \
     com.dedetok.javaservicetest.JavaServiceTest
Hello World!
Daemon started
Working...
Working...
^CShutdown hook triggered
Cleanup complete

 

 

Java Netbeans: upgrade binary Netbeans 29 to Netbeans 30

 This step is straight forward:

  1. go to your root directory (e.g your home dir ~/), and rename old folder e.g ~/netbeans29.
  2. extract netbeans 30 binary and put it in root directory to replace old folder (e.g your home dir ~/).
  3. Run your netbeans 30, import previous configuration
  4. if no error found you safe to remove
    1. old netbeans 29 (e.g ~/netbeans29) 
    2. ~/.netbeans/29
    3. ~/.cache/netbeans/29