Skip to content
 
 

Repository files navigation

fichero-printer

Open your Home Assistant instance and open this repository in HACS

Web GUI, Python CLI, and protocol documentation for the Fichero D11s thermal label printer.

Blog post: Reverse Engineering Action's Cheap Fichero Labelprinter

The Fichero is a cheap Bluetooth thermal label printer sold at Action. Internally it's an AiYin D11s made by Xiamen Print Future Technology. The official app is closed-source and doesn't expose the protocol, so this project reverse-engineers it from the decompiled APK.

The printer

  • 96px wide printhead, 203 DPI
  • Prints 1-bit raster images onto self-adhesive labels (14mm x 30mm default)
  • Connects via BLE or Classic Bluetooth SPP
  • 18500 Li-Ion battery (1200mAh), USB-C charging
  • Bluetooth names: FICHERO_5836, D11s_

Why not just use the app?

The Fichero app (com.lj.fichero) asks for 26 permissions. For a label printer. The notable ones:

ACCESS_FINE_LOCATION         Your precise GPS location
ACCESS_COARSE_LOCATION       Your approximate location
CAMERA                       Your camera
READ_EXTERNAL_STORAGE        Your files
WRITE_EXTERNAL_STORAGE       Your files (write)
READ_MEDIA_IMAGES            Your photos
INTERNET                     Full internet access
ACCESS_WIFI_STATE            Your WiFi info
CHANGE_WIFI_STATE            Change your WiFi settings
CHANGE_WIFI_MULTICAST_STATE  Multicast on your network
AD_ID                        Your advertising ID
ACCESS_ADSERVICES_AD_ID      More ad tracking
ACCESS_ADSERVICES_ATTRIBUTION  Ad attribution tracking
BIND_GET_INSTALL_REFERRER    Where you installed from

Some of these are reasonable. The location permissions exist because of how Android handles Bluetooth. Bluetooth signals can reveal where you physically are, think retail stores using Bluetooth beacons to track which aisle you're standing in. So Android won't let any app scan for Bluetooth devices unless it also has location permission. That's not the app being sneaky. That's Android being cautious.

The camera makes sense too. The app lets you scan barcodes and photograph things to print on labels.

The WiFi permissions are baggage from the underlying SDK. It powers over 159 different printer models, some of which connect over WiFi. The Fichero doesn't use WiFi at all, but the permissions are baked into the shared code.

Then there are four permissions that have nothing to do with printing. Your advertising ID is a unique number assigned to your phone that follows you across every app, letting ad networks build a profile of what you do. The app also wants ad attribution tracking (which apps you installed after seeing an ad) and your install referrer (how you found the app store listing). That's a label printer quietly feeding your activity to an ad network.

The package name is com.lj.fichero but the SDK inside is from a company called LuckPrinter (com.luckprinter.sdk_new). The app is what's called a white-label product: a generic app rebranded with the Fichero name and logo. The same codebase runs receipt printers, A4 thermal printers, and industrial label makers. It supports 159+ printer models across four manufacturers. Your little label printer's app is just a skin on top.

One more reason to ditch the app and talk to the printer directly.

Web GUI

Try it at https://0xmh.github.io/fichero-printer/ - a full label designer with text, images, barcodes, QR codes, and drag-and-drop canvas editing. Built with Svelte 5 and Fabric.js, ported from the NiimBlue project (MIT).

Click the Bluetooth icon, pair with the printer, and start designing. Labels save to browser localStorage. Export as JSON or PNG.

Requires Web Bluetooth, so Chrome/Edge/Opera only. Firefox and Safari don't support it.

CLI Setup

Requires Python 3.10+ and uv. Turn on the printer and run:

uv run fichero info

This auto-discovers the printer via BLE scan. To skip scanning on subsequent runs, find your printer's address from the scan output and save it:

export FICHERO_ADDR=AA:BB:CC:DD:EE:FF

You can also pass it per-command:

uv run fichero --address AA:BB:CC:DD:EE:FF info

CLI Usage

uv run fichero --help

Printing

uv run fichero text "Hello World"
uv run fichero text "Fragile" --density 2 --copies 3
uv run fichero text "Big Label" --font-size 40 --label-height 180
uv run fichero image label.png
uv run fichero image label.png --density 1 --copies 2

Density: 0=light, 1=medium (default), 2=thick.

Text labels accept --font-size (default 24) and --label-height in pixels (default 240).

Device info

uv run fichero info
uv run fichero status

Settings

uv run fichero set density 2
uv run fichero set shutdown 30
uv run fichero set paper gap
  • density - how dark the print is. 0 is faint, 1 is normal, 2 is the darkest. Higher density uses more battery and can smudge on some label stock.
  • shutdown - how many minutes the printer waits before turning itself off when idle (1-480). Set it higher if you're tired of turning it back on between prints.
  • paper - what kind of label stock you're using. gap is the default, for labels with spacing between them (the printer detects the gap to know where to stop). black is for rolls with a black mark between labels. continuous is for receipt-style rolls with no markings.

Library Usage

import asyncio
from fichero import connect, PrinterNotFound

async def main():
    async with connect() as pc:
        info = await pc.get_info()
        print(info)

asyncio.run(main())

The package exports PrinterClient, connect, PrinterError, PrinterNotFound, PrinterTimeout, PrinterNotReady, and PrinterStatus.

Home Assistant integration

This repository includes a local Home Assistant custom integration and a bundled dashboard card for the Fichero/D11s. It can:

  • press an existing SwitchBot entity before starting a printer session;
  • connect through Home Assistant's shared Bluetooth scanner (including a connectable Bluetooth proxy), or use a configured Bluetooth address;
  • automatically wrap text and choose the largest font that fits the configured label length and the 96-pixel printhead;
  • print 1–100 copies, print today's date as dd-mm-yyyy, and persist favorite label shortcuts in Home Assistant;
  • show live powering-on, connecting, connected, printing, error, and disconnected status; and explicitly connect or disconnect/power off.

Install with HACS

Use the Open in HACS button above, or add https://github.com/jonathan-shc/fichero-printer as a custom repository with category Integration. Install Fichero Label Printer, restart Home Assistant, and add the integration under Settings → Devices & services.

HACS installs releases when available and otherwise installs from this repository's default branch.

Manual install

Copy custom_components/fichero_printer into the same directory under your Home Assistant configuration, then restart Home Assistant.

In Home Assistant, go to Settings → Devices & services → Add integration, find Fichero Label Printer, and configure:

  1. The existing SwitchBot switch, button, or input_button entity which physically presses the printer button.
  2. How long the printer needs after that press before Bluetooth is ready.
  3. The physical label length (30 mm by default), density, and whether disconnect should press the SwitchBot again.
  4. Optionally, a fixed Bluetooth address. Leave it blank for name-based discovery (FICHERO… or D11s_…) each time a session starts.

Add the Fichero Label Printer card from the dashboard card picker. With one printer it discovers the status entity automatically. With multiple printers, select the desired status entity in the card editor. The card is served and registered by the integration, so no separate Lovelace resource is needed.

The configured SwitchBot action is treated as a momentary physical press. Make sure its press duration is already correct in Home Assistant, as the integration deliberately does not change the SwitchBot configuration.

Bluetooth connection troubleshooting

After a SwitchBot press, the integration waits for the configured startup delay, then discovers and connects to the printer directly. Connection failures retain their original diagnostic details instead of a generic wake-up timeout.

For org.bluez.Error.BREDR.ProfileUnavailable, BlueZ has selected Bluetooth Classic instead of BLE. The integration tries setting org.bluez.Device1.PreferredBearer to le for this printer on a local adapter and retries once. This optional, experimental BlueZ property may not be available on every host. If unavailable, the error explains the required host configuration or BLE proxy alternative. See the BlueZ Device API.

The Home Assistant integration validates both printer GATT characteristics before reporting a connection. Missing characteristics or stale D-Bus object paths trigger one cache refresh and reconnection with fresh service discovery. Failed or cancelled notification setup releases the connection, as does unloading the integration.

If connection problems persist, enable debug logging for custom_components.fichero_printer and bleak_retry_connector, reproduce the failure, and include the exception, Home Assistant version, and whether you use a local adapter or an ESPHome proxy in your report. Keep other printer apps disconnected while testing. This recovery does not reset the host Bluetooth adapter or remove the printer's pairing from BlueZ.

Run the regression suite with python -m pip install -e . pytest pytest-asyncio bleak-retry-connector dbus-fast followed by python -m pytest -q.

TODO

  • Emoji support in text labels. The default Pillow font has no emoji glyphs, so they render as squares. Needs two-pass rendering: split text into emoji/non-emoji segments, render emoji with Apple Color Emoji (macOS) or Noto Color Emoji (Linux) using embedded_color=True, then composite onto the label.

Protocol and reverse engineering

See docs/PROTOCOL.md for the full command reference, print sequence, and how this was reverse-engineered.

License

MIT

About

Fichero D11s thermal label printer - BLE protocol reverse engineering and Python CLI tool

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages