I was able to search and pair a Raspberry Pi 4 to a Bluetooth 4.0 thermal printer using the BlueZ API.
In order to use the python-escpos library, I need to create a serial port /dev/rfcomm
, which I can do with sudo rfcomm bind /dev/rfcomm0 XX:XX:XX:XX:XX:XX 1
.
How can I do it programatically in Python (without having to use python-subprocess
)?
rfcomm
was one of the tools deprecated by the BlueZ project in 2017. I would suggest that you avoid using functionality related to that.
The python-escpos
library takes the location of a serial port device so I would suggest using the Python pty library which creates two pseudo-devices, the pts, emulates a hardware serial port device.
How exactly you want to architect this will depend on your project but I did a simple test where I had a script creating a pseudo serial port that it listened on and sent to the BLE device if data was received:
import os
import pty
from time import sleep
import pydbus
dev_addr = 'xx:xx:xx:xx:xx:xx'
ptmx_fd, pts_fd = pty.openpty()
pts_name = os.ttyname(pts_fd)
print(f"Printer port: {pts_name}")
bus = pydbus.SystemBus()
mngr = bus.get('org.bluez', '/')
def get_characteristic_path(dev_path, uuid):
mng_objs = mngr.GetManagedObjects()
for path in mng_objs:
chr_uuid = mng_objs[path].get('org.bluez.GattCharacteristic1', {}).get('UUID')
if path.startswith(dev_path) and chr_uuid == uuid.casefold():
return path
class MyRemoteDevice:
# CHAR_UUID = '0000ff02-0000-1000-8000-00805f9b34fb' # Real printer
CHAR_UUID = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E' # my test device
def __init__(self, mac_addr):
device_path = f"/org/bluez/hci0/dev_{mac_addr.replace(':', '_')}"
self.device = bus.get('org.bluez', device_path)
# Placeholder for characteristic details
self.characteristic = None
def _get_gatt_details(self):
char_path = get_characteristic_path(self.device._path,
MyRemoteDevice.CHAR_UUID)
self.characteristic = bus.get('org.bluez', char_path)
def connect(self):
self.device.Connect()
# Check GATT services have been resolved before continuing
while not self.device.ServicesResolved:
sleep(0.25)
self._get_gatt_details()
def disconnect(self):
self.device.Disconnect()
def read(self):
return self.characteristic.ReadValue({})
def write(self, new_value):
self.characteristic.WriteValue(new_value, {})
my_first_dev = MyRemoteDevice(dev_addr)
my_first_dev.connect()
try:
while True:
data = os.read(ptmx_fd, 1000)
if data:
print("data received:", data)
my_first_dev.write(data)
except:
pass
finally:
my_first_dev.disconnect()
In a Python prompt I then sent values to the serial port using the escpos library:
from escpos.printer import Serial
# 9600 Baud, 8N1, Flow Control Enabled
p = Serial(devfile='/dev/pts/3',
baudrate=9600,
bytesize=8,
parity='N',
stopbits=1,
timeout=1.00,
p.text("Hello Printer#")