A Secret Message Printer with Toit and ESP32

Flutter and the Dart ecosystem struggles to provide a capable Bluetooth Stack. For a stable product, I decided to proxy the communications with my thermal printer through an ESP32.

The thing I am trying to build will expose ESPs’ bluetooth capability through an onboard web server. Through this I will be able to send any commands to the printer over Wi-Fi, and ESP will handle the stream of Bytes.

The first prototype for this needed for me to connect my ESP with the thermal printer over bluetooth to print anything on the printer.

It started with getting an app called nRF connect on the phone.

https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp&hl=en&gl=US&pli=1

With this I scanned my homespace and confirmed that the printer I need to work with has BLE capabilities. I’m using an ATPoS 401.

As scary as BLE sounds, it is simple enough:

  1. Scan through the central and connect with a device
  2. Scan device for services
  3. Scan each service for characteristics
  4. One of the above characteristics will support write
  5. Write ByteArray to the said characteristic

Manufacturer provided an ESC command guide to get ByteArrrays for the desired action, and I will try to build a library for it.. But I built an interesting program with what I found:

import ble
import bytes

/**
ESC Commands...
*/
CUT ::= #[0x1d, 0x56, 0x00]


find-device-for-service central /ble.Central --service/ble.BleUuid  -> ble.RemoteScannedDevice:
  scan-duration_ := Duration --s=3
  central.scan --duration=scan-duration_ : | device /ble.RemoteScannedDevice|
    if device.data.service-classes.contains (ble.BleUuid "18f0"):
      return device
  throw "Device not found"

get-write-characteristic-from-peripheral peripheral /ble.RemoteDevice -> ble.RemoteCharacteristic:
  peripheral.discover-services
  peripheral.discovered-services.do: |service /ble.RemoteService |
    service.discover-characteristics
    service.discovered-characteristics.do: |characteristic /ble.RemoteCharacteristic |
      if service.uuid == (ble.BleUuid "18f0") and characteristic.properties == 12:
        return characteristic
  throw "correct characteristic not found"

list-everything-for-peripheral peripheral /ble.RemoteDevice:
  services := peripheral.discover-services
  peripheral.discovered-services.do: |service /ble.RemoteService|
    service.discover-characteristics
    service.discovered-characteristics.do: | characteristic /ble.RemoteCharacteristic |
      characteristic.discover-descriptors
      print "$service.uuid/$characteristic.uuid properties: $characteristic.properties" 


main:
  adapter_ := ble.Adapter 
  central := ble.Central adapter_
  device-to-connect /ble.RemoteScannedDevice := find-device-for-service central --service=(ble.BleUuid "18f0")
  print "Device to connect: $device-to-connect.data.service-classes"
  peripheral /ble.RemoteDevice := central.connect device-to-connect.address

  write-characteristic /ble.RemoteCharacteristic := get-write-characteristic-from-peripheral peripheral
  print "$write-characteristic.properties"
  write-characteristic.write #[0x1b, 0x4A, 0x01]/// move lines
  write-characteristic.write "Hello Nancy!\nThis is a secret message written just for you.\nYou are loved :)".to-byte-array
  write-characteristic.write #[0x1b, 0x4A, 0x01]/// move lines
  write-characteristic.write CUT

With this, every time I would turn my ESP on, a secret message will be printed out from the printer.

With this today ended with good success, and good learning around ESP’s BLE capabilities and Toit’s adaptation of the same.