API reference#
The phomemo package, as installed from PyPI.
Printer#
High-level async printer client.
The Printer class is the primary developer-facing API. It composes
the transport, protocol, event, and imaging modules into a single
coherent interface for controlling Phomemo thermal printers.
Typical usage:
from phomemo import Printer, Density
async with Printer("m08f", "AA:BB:CC:DD:EE:FF") as printer:
await printer.connect()
# Check device state before printing
info = await printer.query_device_info()
print(f"Battery: {info.battery}%, Lid: {info.lid}, Paper: {info.paper}")
# Wait for a sheet, print, feed it out
await printer.wait_for_ready()
await printer.print_image("photo.png", density=Density.MEDIUM)
await printer.eject_paper()
- exception phomemo.printer.PrintAborted(reason)[source]#
Bases:
RuntimeErrorA raster transfer stopped before the page was complete.
- Parameters:
reason (str)
- Return type:
None
- reason#
Short human-readable cause, e.g.
"cancelled".
- exception phomemo.printer.SheetRanOut(reason)[source]#
Bases:
PrintAbortedThe sheet left the paper sensor before the raster was printed.
- Parameters:
reason (str)
- Return type:
None
- class phomemo.printer.DeviceInfo(battery=None, lid=None, paper=None, firmware=None, serial=None, auto_off_minutes=None)[source]#
Bases:
objectSnapshot of device state collected from query responses.
- Parameters:
battery (int | None)
lid (LidState | None)
paper (PaperState | None)
firmware (str | None)
serial (str | None)
auto_off_minutes (int | None)
- battery#
Battery percentage (0-100), or None if not queried.
- Type:
int | None
- lid#
Lid state, or None if not queried.
- Type:
phomemo.events.LidState | None
- paper#
Paper state, or None if not queried.
- Type:
phomemo.events.PaperState | None
- firmware#
Firmware version string, or None if not queried.
- Type:
str | None
- serial#
Serial number string, or None if not queried.
- Type:
str | None
- auto_off_minutes#
Auto-off timer in minutes (0 = disabled), or None if not queried.
- Type:
int | None
- class phomemo.printer.Printer(profile='m08f', address=None)[source]#
Bases:
objectAsync BLE client for Phomemo thermal printers.
Manages the full lifecycle: BLE connection, device queries, image preparation, raster printing, and paper transport. Designed to be used as an async context manager.
- Parameters:
profile (str | PrinterProfile) – Either a profile name string (e.g.
"m08f") or aPrinterProfileinstance.address (str | BLEDevice | None) – BLE MAC address (e.g.
"AA:BB:CC:DD:EE:FF"), resolved by a targeted scan atconnect()time, or aBLEDevicefromdiscover(), used as is. If omitted,connect()auto-discovers a nearby device matching the profile’sble_name_pattern.
- property profile: PrinterProfile#
The active printer hardware profile.
- property is_connected: bool#
Whether the BLE connection is active.
- property address: str | None#
The printer’s BLE address, once known.
- property chunk_bytes: int#
Bytes per BLE write on the current connection.
- property rows_sent: int#
Raster rows handed to the transport in the current transfer, else 0.
- on_event(callback)[source]#
Register a listener for parsed device events.
Callbacks receive typed event dataclasses (
LidEvent,PaperEvent,BatteryEvent,MotorStopEvent, etc.) as they arrive from the printer.- Parameters:
callback (Callable[[DeviceEvent], None]) – Called with each parsed
DeviceEvent.- Return type:
None
- async connect(discovery_timeout=5.0)[source]#
Connect to the printer.
The transport always receives a
BLEDevicefrom a live scan: BlueZ can only connect to a device it has seen advertising recently, so a bare MAC address is resolved through a targeted scan first. Without anaddress, scans for a nearby device whose advertised name matches the profile’sble_name_pattern, connects to it and keeps its address for later connects; several matches are refused rather than picking one.- Parameters:
discovery_timeout (float) – Scan duration in seconds, for both name-based discovery and MAC resolution. Ignored if a
BLEDevicewas provided at instantiation.- Raises:
ConnectionError – If the connection fails, if a name scan finds no matching device or several, or if the given MAC address is not seen within
discovery_timeout.RuntimeError – If already connected.
- Return type:
None
- async disconnect()[source]#
Disconnect from the printer.
Safe to call even if not connected.
- Return type:
None
- async initialize()[source]#
Send
ESC @to reset the printer to its default state.Should precede standalone ESC-prefix commands to prevent the BLE bridge chip from intercepting them.
- Return type:
None
- async set_density(level)[source]#
Set print concentration via
ESC N 04.Persists until the next
ESC @reset. A model without density control ignores the call.- Parameters:
level (Density) – Desired concentration level.
- Return type:
None
- async feed(lines=20)[source]#
Feed paper by the given number of lines via
ESC d.Each line is approximately one dot row (0.125mm at 203 DPI).
- Parameters:
lines (int) – Number of lines to feed (1-255).
- Return type:
None
- async eject_paper(max_feeds=64, step_rows=120, ahead=2, feed_seconds=0.7, clear_rows=160)[source]#
Feed the sheet out until the sensor reports it gone, then clear the rollers.
Feeds of
step_rows(15mm by default) are keptaheaddeep in the printer’s queue so the motor runs without pauses: one more goes out wheneverfeed_seconds(about one section at the measured feed speed) pass without the paper-absent event. On the event, one feed ofclear_rowspushes the sheet out of the rollers. A sheet already past the sensor, or a printer that does not answer the initial query, gets three feeds ofclear_rowsblind.- Parameters:
max_feeds (int) – Maximum number of feeds before giving up (about 1m).
step_rows (int) – Rows per feed.
ahead (int) – Feeds queued before waiting for the sensor event.
feed_seconds (float) – Wait per feed for the sensor event before queuing the next one; longer than the feed itself stalls the motion, shorter queues ahead of the motor.
clear_rows (int) – Rows fed once the sensor is clear.
- Returns:
Trueonce the sheet has left the sensor,Falseif it is still present aftermax_feedsfeeds.- Return type:
bool
- async set_auto_off_timer(minutes)[source]#
Set the auto-off timer.
- Parameters:
minutes (int) – Timeout in minutes, a multiple of 5 up to
AUTO_OFF_MAX_MINUTES. 0 disables the timer.- Raises:
ValueError – If minutes is out of range or not a multiple of 5.
- Return type:
None
- async query_battery(timeout=1.0)[source]#
Query the current battery level.
- Parameters:
timeout (float) – Seconds to wait for a response.
- Returns:
Battery percentage (0-100), or None if no response.
- Return type:
int | None
- async query_firmware(timeout=1.0)[source]#
Query the firmware version.
- Parameters:
timeout (float) – Seconds to wait for a response.
- Returns:
Version string (e.g.
"1.1.3"), or None if no response.- Return type:
str | None
- async query_serial(timeout=1.0)[source]#
Query the device serial number (ASCII form).
- Parameters:
timeout (float) – Seconds to wait for a response.
- Returns:
Serial number string, or None if no response.
- Return type:
str | None
- async query_lid(timeout=1.0)[source]#
Query the lid state.
- Parameters:
timeout (float) – Seconds to wait for a response.
- Returns:
LidState.CLOSEDorLidState.OPEN, or None.- Return type:
LidState | None
- async query_paper(timeout=1.0)[source]#
Query the paper sensor state.
Important: Paper state is unreliable when the lid is open. Always query lid state first.
- Parameters:
timeout (float) – Seconds to wait for a response.
- Returns:
PaperState.PRESENTorPaperState.ABSENT, or None.- Return type:
PaperState | None
- async query_auto_off(timeout=1.0)[source]#
Query the auto-off timer.
- Parameters:
timeout (float) – Seconds to wait for the response.
- Returns:
Timeout in minutes (0 = disabled), or
Noneif the printer did not answer.- Return type:
int | None
- async query_device_info(timeout=1.0)[source]#
Query all available device information.
Sends battery, firmware, serial, lid, paper, and timer queries sequentially. Each query returns as soon as the device responds (typically ~70ms), so the full round-trip is well under 1s.
Paper state is discarded if the lid is open (sensor unreliable).
- Parameters:
timeout (float) – Per-query timeout in seconds.
- Returns:
A
DeviceInfowith all available fields populated.- Return type:
- async check_ready(timeout=1.0)[source]#
Check whether the printer is ready to print.
Queries lid and paper state. Returns a tuple of
(ready, reason)wherereadyisTrueif the printer can accept a print job.- Parameters:
timeout (float) – Per-query timeout in seconds.
- Returns:
(True, "ready")or(False, reason_string).- Return type:
tuple[bool, str]
- async reconnect(discovery_timeout=5.0)[source]#
Drop and re-establish the BLE connection to the same device.
A printer that ran a raster past the end of the sheet stops answering queries and discards further print data until the connection is re-established.
- Parameters:
discovery_timeout (float) – Scan budget if the device has to be found again.
- Return type:
None
- async wait_for_ready(timeout=60.0, poll=0.5, settle=3.0, mute_threshold=3)[source]#
Block until a sheet is loaded and seated at the print head.
Polls
check_readyso a caller can start a page job and let the user insert the sheet afterwards. The paper sensor reports the sheet as soon as its edge arrives; the feed motor keeps pulling for about two more seconds and then the printer repeats the paper-present event.settlewaits for that repeat (capped) so raster data is not sent while the sheet is still moving.mute_thresholdconsecutive query timeouts mean the printer is in the error state left by a sheet overrun; the connection is dropped and re-established once, which clears it.- Parameters:
timeout (float) – Maximum seconds to wait for a sheet.
poll (float) – Seconds between readiness checks.
settle (float) – Maximum seconds to wait for the feed to complete after the sheet is detected;
0sends as soon as it is detected.mute_threshold (int) – Consecutive query timeouts before a reconnect.
- Raises:
TimeoutError – With the last readiness reason as message.
- Return type:
None
- async print_bitmap(bitmap, height, density=Density.MEDIUM, mode=ScaleMode.NORMAL, feed_lines=20, on_progress=None, wait_for_completion=True, completion_timeout=30.0, abort=None, short_sheet_fraction=0.25)[source]#
Send pre-rendered bitmap data to the printer as one continuous stream.
- Parameters:
bitmap (bytes) – Packed 1-bit bitmap (
width_bytes * heightbytes).height (int) – Number of rows in the bitmap.
density (Density | None) – Print concentration (None to skip).
mode (ScaleMode) – GS v 0 scaling mode.
feed_lines (int) – Paper feed lines after printing.
on_progress (Callable[[int, int], None] | None) – Progress callback
(chunks_sent, total_chunks)per connection-sized chunk.wait_for_completion (bool) – If True, block until the motor-stop signal is received and confirm the printer still answers.
completion_timeout (float) – Maximum seconds to wait for completion.
abort (Event | None) – Set it to stop the transfer; the band in progress is completed with white rows so the printer stays in sync.
short_sheet_fraction (float) – A paper-absent event while more than this fraction of rows is still unsent means the sheet is shorter than the page.
- Raises:
RuntimeError – If not connected.
TimeoutError – If completion signal not received within timeout.
PrintAborted – If
abortwas set;reasonis"cancelled".SheetRanOut – If the sheet ran out early (paper-absent while most of the page is unsent, or the printer muted after the motor stop).
PrintAborted("lid opened")if the lid was open when the motor stopped: the printer discards data in that state.
- Return type:
None
- async print_image(source, density=Density.MEDIUM, fit=ImageFit.FIT_WIDTH, dither=DitherMode.FLOYD_STEINBERG, feed_lines=20, on_progress=None, wait_for_completion=True, completion_timeout=30.0)[source]#
Full print pipeline: load image, process, print, feed.
Accepts a file path or an already-opened PIL Image. Handles the complete pipeline from image to paper.
- Parameters:
source (str | Path | Image) – Path to an image file, or a PIL
Imageinstance.density (Density | None) – Print concentration (None to skip).
fit (ImageFit) – How to fit the image to the print area.
FIT_PAGEbounds the result by the profile’smax_rowsas well as its width.dither (DitherMode) – Dithering algorithm for 1-bit conversion.
feed_lines (int) – Paper feed lines after printing.
on_progress (Callable[[int, int], None] | None) – Progress callback
(chunks_sent, total_chunks).wait_for_completion (bool) – If True, block until print-complete signal.
completion_timeout (float) – Maximum seconds to wait for completion.
- Raises:
RuntimeError – If not connected.
FileNotFoundError – If the source path doesn’t exist.
ValueError – If
fitisFIT_PAGEand the profile has nomax_rows.
- Return type:
None
Discovery#
BLE device discovery for Phomemo printers.
Wraps bleak.BleakScanner to find nearby BLE devices, with optional
regex filtering on advertised names.
- async phomemo.discovery.discover(name_pattern=None, timeout=5.0)[source]#
Discover nearby BLE devices, optionally filtered by name pattern.
- Parameters:
name_pattern (str | None) – If provided, only return devices whose advertised name matches this regex pattern (searched, not full-match).
timeout (float) – Scan duration in seconds.
- Returns:
List of discovered
BLEDeviceobjects, sorted by name.- Raises:
ConnectionError – If the Bluetooth adapter is unavailable or the scan fails at the OS/adapter level.
- Return type:
list[BLEDevice]
Profiles#
Printer profile registry.
Each profile captures the physical and protocol characteristics of a
specific Phomemo printer model: print width, BLE UUIDs, timing
constraints, and supported features. The profile system is extensible —
add new models by registering a PrinterProfile instance via
register_profile.
- class phomemo.registry.PrinterProfile(name, ble_name_pattern, print_width_px, dpi=203, max_chunk_bytes=244, negotiate_mtu=True, write_with_response=True, chunk_delay_s=0.0, band_height=256, sheet_length_mm=None, top_margin_mm=0.0, bottom_margin_mm=0.0, service_uuid='0000ff00-0000-1000-8000-00805f9b34fb', write_uuid='0000ff02-0000-1000-8000-00805f9b34fb', notify_uuid='0000ff01-0000-1000-8000-00805f9b34fb', status_uuid='0000ff03-0000-1000-8000-00805f9b34fb', density_levels=None, supports_escpos_queries=False, make='Phomemo', model_name='', media=(), default_media=None)[source]#
Hardware and protocol parameters for a Phomemo printer model.
- Parameters:
name (str)
ble_name_pattern (str)
print_width_px (int)
dpi (int)
max_chunk_bytes (int)
negotiate_mtu (bool)
write_with_response (bool)
chunk_delay_s (float)
band_height (int)
sheet_length_mm (float | None)
top_margin_mm (float)
bottom_margin_mm (float)
service_uuid (str)
write_uuid (str)
notify_uuid (str)
status_uuid (str)
density_levels (tuple[int, int, int] | None)
supports_escpos_queries (bool)
make (str)
model_name (str)
media (tuple[str, ...])
default_media (str | None)
- name#
Lower-case model identifier (e.g.
"m08f"), also the name of the model’s manifest directory.- Type:
str
- ble_name_pattern#
Regex pattern matched against BLE advertisement names during device discovery.
- Type:
str
- print_width_px#
Print head width in dots/pixels.
- Type:
int
- dpi#
Print resolution in dots per inch.
- Type:
int
- max_chunk_bytes#
Maximum BLE write payload in bytes. Determined by the negotiated ATT MTU minus 3 bytes of ATT overhead.
- Type:
int
- negotiate_mtu#
If
True(default), the transport will attempt to read the negotiated BLE MTU at connect time and derive the effective chunk size from it (MTU minus 3 bytes ATT overhead). Falls back tomax_chunk_bytesif the MTU cannot be determined.- Type:
bool
- write_with_response#
Use ATT Write Request (
True, default) rather than Write Command for every write. The printer delays its response while its receive buffer is full, so the stream is paced by the print head and never overflows. Unacknowledged writes needchunk_delay_sand still overflow on long jobs.- Type:
bool
- chunk_delay_s#
Minimum delay between BLE writes in seconds.
0.0(default) withwrite_with_response; only unacknowledged writes need a delay.- Type:
float
- band_height#
Maximum rows per GS v 0 raster command.
- Type:
int
- sheet_length_mm#
Length of one sheet in the feed direction, or
Nonefor continuous roll media.- Type:
float | None
- top_margin_mm#
Unprintable lead from the paper edge to the first printed row, set by the distance between the paper sensor and the print head.
- Type:
float
- bottom_margin_mm#
Rows kept free at the sheet end so the raster plus trailing feed never runs the sheet out of the sensor mid-job; an overrun leaves the printer in an error state.
- Type:
float
- service_uuid#
BLE GATT service UUID for the print data service.
- Type:
str
- write_uuid#
BLE characteristic UUID for writing commands/data.
- Type:
str
- notify_uuid#
BLE characteristic UUID for device events (
ff01). All meaningful notifications arrive here: sensor state changes, query responses, and print completion signals.- Type:
str
- status_uuid#
BLE characteristic UUID for the status echo channel (
ff03). Echoes01 01for most writes and sends a fixed connect greeting on startup. Does not carry query responses or actionable device state; useful only for low-level debugging.- Type:
str
- density_levels#
ESC N 04concentration values for the low, medium and highDensitylevels, orNonewhen the model has no density control.- Type:
tuple[int, int, int] | None
- supports_escpos_queries#
Whether standard ESC/POS queries return meaningful data (False for M08F — use Phomemo queries instead).
- Type:
bool
- make#
Manufacturer as shown to users.
- Type:
str
- model_name#
Model as the vendor writes it (
"M08F");nameis the lower-case identifier.- Type:
str
- media#
PWG names of the sheet sizes the model takes.
- Type:
tuple[str, …]
- default_media#
The medium jobs get when they name none.
- Type:
str | None
- rows_for(length_mm)[source]#
Dot rows that fit between the margins of a sheet of the given length.
- Parameters:
length_mm (float | None) – Sheet length in the feed direction, or
Nonefor roll media.- Returns:
Printable rows, or
Nonefor roll media.- Raises:
ValueError – If the margins leave no printable length.
- Return type:
int | None
- property max_rows: int | None#
Printable rows of the default sheet,
Nonefor roll media.
- property lead_rows: int#
the sheet lead the head cannot reach.
- Type:
Rows covered by the top margin
- property width_bytes: int#
Print width in bytes (8 pixels per byte, MSB-first).
- phomemo.registry.get_profile(name)[source]#
Look up a registered printer profile by name.
- Parameters:
name (str) – Profile key (e.g.
"m08f").- Returns:
The matching
PrinterProfile.- Raises:
KeyError – If no profile is registered under that name.
- Return type:
- phomemo.registry.list_profiles()[source]#
Return the names of all registered printer profiles.
- Returns:
Sorted list of profile name strings.
- Return type:
list[str]
- phomemo.registry.register_profile(profile)[source]#
Register a custom printer profile.
Allows third-party code to add profiles for printer models not shipped with this library.
- Parameters:
profile (PrinterProfile) – The profile to register. Overwrites any existing profile with the same name.
- Return type:
None
- phomemo.registry.profile_for_name(ble_name)[source]#
The registered profile whose name pattern matches an advertised name.
- Parameters:
ble_name (str | None) – Name the printer advertises over Bluetooth.
- Returns:
The first matching profile in identifier order, or
None.- Return type:
PrinterProfile | None
- phomemo.registry.load_manifest(model_dir)[source]#
Build a profile from a model manifest directory.
The directory holds
model.jsonand the model’s icons; its name is the model identifier.- Parameters:
model_dir (Path) – The model’s manifest directory.
- Returns:
The profile the manifest defines.
- Raises:
ValueError – If
model.jsondoes not parse, or a field is missing, of the wrong type or inconsistent; the message names file and field.OSError – If
model.jsoncannot be read.
- Return type:
Images and pages#
Image preparation pipeline for thermal printing.
Converts arbitrary images into 1-bit raster bitmaps suitable for Phomemo printers. The pipeline handles resizing, padding/cropping, grayscale conversion, and dithering.
Bitmap format (from the M08F Protocol Reference):
- 1 bit per pixel, packed into bytes.
- 1 = black (ink on), 0 = white (no ink).
- Most significant bit of each byte is the leftmost pixel.
- Rows are sequential top-to-bottom.
- class phomemo.imaging.DitherMode(*values)[source]#
Image dithering algorithm for 1-bit conversion.
FLOYD_STEINBERGproduces the best visual quality for photographic content.THRESHOLDapplies a simple threshold at value 128 with no dithering.
- class phomemo.imaging.ToneMode(*values)[source]#
How 8-bit gray becomes the head’s 1-bit output.
THRESHOLDsplits at mid gray (true black and white, crisp text).ORDEREDuses an 8x8 Bayer pattern (even tone, cheap).DIFFUSIONuses Floyd-Steinberg error diffusion (photos).
- phomemo.imaging.prepare_image(img, target_width, fit=ImageFit.FIT_WIDTH, dither=DitherMode.FLOYD_STEINBERG, target_height=None, max_height=None)[source]#
Resize and dither an image for thermal printing.
Processes the image through the full pipeline: resize to target dimensions, pad or crop to exact width (multiple of 8), convert to grayscale, and dither to 1-bit.
- Parameters:
img (Image) – Source PIL Image (any mode).
target_width (int) – Desired width in pixels. Rounded down to the nearest multiple of 8.
fit (ImageFit) – How to fit the image to the target dimensions.
dither (DitherMode) – Dithering algorithm for 1-bit conversion.
target_height (int | None) – Required for
FIT_HEIGHTandSTRETCHmodes.max_height (int | None) – Required for
FIT_PAGE: the image is scaled to fit withintarget_widthxmax_heightpreserving aspect ratio.
- Returns:
A 1-bit (mode
"1") PIL Image ready for bitmap conversion.- Raises:
ValueError – If
target_heightormax_heightis required by the fit mode but not provided.- Return type:
Image
- phomemo.imaging.image_to_bitmap(img)[source]#
Convert a 1-bit PIL Image to packed bitmap bytes.
Each row is packed into
width / 8bytes. Black pixels (value 0) map to bit value 1 (ink on), white pixels (value 255) map to bit value 0 (no ink). MSB of each byte is the leftmost pixel.- Parameters:
img (Image) – A mode
"1"PIL Image.- Returns:
Packed bitmap bytes, row by row.
- Raises:
ValueError – If the image mode is not
"1".- Return type:
bytes
- phomemo.imaging.prepare_page(img, profile, length_mm, tone, rotate=False)[source]#
Map a client page raster onto the printable area of a sheet.
The raster is optionally rotated a quarter turn counter-clockwise (an A5 portrait page printed on a sheet fed long edge first), centred on the head width when narrower and cropped when wider, stripped of the rows that fall into the unprintable top lead, and clipped to the rows the sheet can hold. Gray input is converted with
tone; 1-bit input keeps its pixels.- Parameters:
img (Image) – Page raster, mode
L(0 = black) or mode1.profile (PrinterProfile) – Printer geometry: head width, dpi, margins.
length_mm (float | None) – Sheet length, or
Nonefor roll media (no clipping).tone (ToneMode) – Conversion for gray input; ignored for 1-bit input.
rotate (bool) – Rotate the raster 90 degrees counter-clockwise first.
- Returns:
A mode
1imageprofile.print_width_pxwide.- Return type:
Image
Events#
Device event parsing for Phomemo printer notifications.
All events arrive on the ff01 BLE characteristic as 1a <sub-type>
<data> messages. Events can be spontaneous (triggered by physical
state changes) or solicited (responses to 1f 11 XX queries). Both
use the same 1a-prefixed format.
Multiple 3-byte events can arrive concatenated in a single BLE notification. The parser consumes 3 bytes at a time.
- class phomemo.events.EventKind(*values)[source]#
Event sub-type byte in
1a <sub-type> <data>messages.Maps the second byte of each event to its semantic meaning.
- class phomemo.events.PaperState(*values)[source]#
Paper presence as reported by the rear optical sensor.
- class phomemo.events.DeviceEvent(kind, raw=b'')[source]#
Base class for all device events.
Used directly as a fallback for unrecognised event sub-types.
- Parameters:
kind (int)
raw (bytes)
- kind#
The event sub-type byte.
- Type:
int
- raw#
The original raw bytes from the notification.
- Type:
bytes
- class phomemo.events.LidEvent(kind, raw=b'', lid=LidState.CLOSED)[source]#
Lid state change event.
- Parameters:
kind (int)
raw (bytes)
lid (LidState)
- lid#
Current lid state.
- Type:
- class phomemo.events.PaperEvent(kind, raw=b'', paper=PaperState.ABSENT)[source]#
Paper presence change event.
- Parameters:
kind (int)
raw (bytes)
paper (PaperState)
- paper#
Current paper state.
- class phomemo.events.BatteryEvent(kind, raw=b'', percent=0)[source]#
Battery level report.
- Parameters:
kind (int)
raw (bytes)
percent (int)
- percent#
Battery charge percentage (0-100).
- Type:
int
- class phomemo.events.FirmwareEvent(kind, raw=b'', major=0, minor=0, patch=0)[source]#
Firmware version report.
The version bytes map to
major.minor.patch. Example:1a 07 01 01 03→ v1.1.3.- Parameters:
kind (int)
raw (bytes)
major (int)
minor (int)
patch (int)
- major#
Major version number.
- Type:
int
- minor#
Minor version number.
- Type:
int
- patch#
Patch version number.
- Type:
int
- class phomemo.events.SerialEvent(kind, raw=b'', value='')[source]#
Serial number report (ASCII or short form).
- Parameters:
kind (int)
raw (bytes)
value (str)
- value#
The serial string or hex representation.
- Type:
str
- class phomemo.events.TimerEvent(kind, raw=b'', value=0, minutes=0)[source]#
Auto-off timer setting report.
- Parameters:
kind (int)
raw (bytes)
value (int)
minutes (int)
- value#
Raw timer byte. 0 = disabled, non-zero = timeout in 5-minute increments.
- Type:
int
- minutes#
Computed timeout in minutes (0 = disabled). Derived from
value * 5; cannot be set independently.- Type:
int
- class phomemo.events.MotorStopEvent(kind, raw=b'')[source]#
Motor stop / print complete signal.
Fires when the motor stops after a print job. The third byte (
0x0c) is invariant across all tested conditions.- Parameters:
kind (int)
raw (bytes)
- phomemo.events.parse_notification(data)[source]#
Parse a BLE notification payload into typed events.
Notifications from
ff01can contain one or more concatenated 3-byte events. This function splits the payload and parses each event individually.- Parameters:
data (bytes) – Raw bytes from a BLE notification on
ff01.- Returns:
List of parsed
DeviceEventinstances. Empty list if the data doesn’t start with0x1aor has invalid length.- Return type:
list[DeviceEvent]
Bridge client#
Client for the bridge socket, used by the CLI and by printer-application tests.
- exception phomemo.bridge.client.BridgeError[source]#
The bridge refused or failed a command; the message is its
error.
- class phomemo.bridge.client.BridgeClient(socket_path, on_event=None)[source]#
One connection to the bridge.
- Parameters:
socket_path (Path) – The bridge’s unix socket.
on_event (Callable[[dict[str, Any]], None] | None) – Called with each pushed event while a reply is pending.
- async send(obj, payload=b'')[source]#
Send a command without waiting for its reply.
- Parameters:
obj (dict[str, Any])
payload (bytes)
- Return type:
None
- async reply()[source]#
Read the reply to the pending command, dispatching events on the way.
The bridge acknowledges an
abortsent while another command is pending before it answers that command; the acknowledgement is skipped here.- Raises:
BridgeError – If the reply reports
ok: false.- Return type:
dict[str, Any]
- async call(obj, payload=b'')[source]#
Send a command and return its reply.
- Parameters:
obj (dict[str, Any])
payload (bytes)
- Return type:
dict[str, Any]
- async open(address=None)[source]#
Bring the printer connection up.
- Parameters:
address (str | None) – Printer to connect to;
Nonekeeps the bridge’s choice (configured address, the last printer, or a name scan).- Returns:
connectedand, when that is false, thereason.- Return type:
dict[str, Any]
- async drop_link()[source]#
Drop the printer connection now instead of after the idle timeout.
- Return type:
None
- async auto_off(minutes=None)[source]#
Read the linked printer’s auto-off timer, setting it first if given.
- Parameters:
minutes (int | None) – New timeout, a multiple of 5; 0 = never switch off.
- Returns:
The timer in minutes as the printer reports it.
- Return type:
int | None
- async status(address=None)[source]#
Connection state and sensors;
last_seenvalues without a connection.- Parameters:
address (str | None) – Printer to report on;
Nonemeans the linked or last linked one.- Return type:
dict[str, Any]
- async test_page(versions=None)[source]#
Render the test page and return the PNG’s path.
- Parameters:
versions (dict[str, str] | None) – Component versions to print, by name.
- Return type:
Path
- async print_test_page(quality='normal')[source]#
Render the test page and print it through the bridge.
The page covers the area below the sheet’s unprintable lead, so it gets that lead as white rows on top before the normal page preparation drops them again.
- Parameters:
quality (str) –
draft,normalorhigh.- Returns:
Impressions printed (1).
- Return type:
int
- async print_image(path, media='a4', tone='auto', quality='normal', content='auto', abort_after=None)[source]#
Print an image file as one page: open, wait for a sheet, stream, end.
- Parameters:
path (Path) – Image file readable by Pillow.
media (str) –
a4,a5(fed long edge first, page rotated) orroll.tone (str) –
autoor aToneModevalue.quality (str) –
draft,normalorhigh(maps to density).content (str) –
auto,text,graphicorphoto.abort_after (float | None) – Seconds after
page_endto sendabort; for testing.
- Returns:
Impressions printed (1).
- Raises:
BridgeError – If any step fails.
KeyError – If
mediaorqualityis not known.
- Return type:
int
Bridge configuration#
Bridge configuration: TOML files layered under environment overrides.
- exception phomemo.bridge.config.ConfigError[source]#
A configuration file named explicitly does not exist.
- phomemo.bridge.config.default_paths(env)[source]#
System file first, then the user’s XDG config file.
- Parameters:
env (Mapping[str, str]) – Environment to read
XDG_CONFIG_HOMEandHOMEfrom.- Returns:
Candidate paths in override order; missing files are skipped later.
- Return type:
list[Path]
- phomemo.bridge.config.default_socket(env, system_socket=None)[source]#
The system bridge’s socket when it exists, else one under
XDG_RUNTIME_DIR.The system service listens at
/run/phomemo/bridge.sock; a user’s command line talks to it when it is there. Without it (development, a user service) the socket lives in the user’s runtime directory.- Parameters:
env (Mapping[str, str]) – Environment providing
XDG_RUNTIME_DIR.system_socket (Path | None) – The system bridge’s socket;
SYSTEM_SOCKETby default.
- Returns:
The socket path to listen on or connect to.
- Return type:
Path
- phomemo.bridge.config.load_config(paths=None, env=environ({'ACCEPT_EULA': 'Y', 'ACTIONS_ORCHESTRATION_ID': 'f41a3352-3a67-8e14-ab2d-1ce5b22a710f.build.__default', 'ACTIONS_RUNNER_ACTION_ARCHIVE_CACHE': '/opt/actionarchivecache', 'ACTIONS_RUNNER_RETURN_JOB_RESULT_FOR_HOSTED': '1', 'AGENT_TOOLSDIRECTORY': '/opt/hostedtoolcache', 'ANDROID_HOME': '/usr/local/lib/android/sdk', 'ANDROID_NDK': '/usr/local/lib/android/sdk/ndk/27.3.13750724', 'ANDROID_NDK_HOME': '/usr/local/lib/android/sdk/ndk/27.3.13750724', 'ANDROID_NDK_LATEST_HOME': '/usr/local/lib/android/sdk/ndk/30.0.16248370', 'ANDROID_NDK_ROOT': '/usr/local/lib/android/sdk/ndk/27.3.13750724', 'ANDROID_SDK_ROOT': '/usr/local/lib/android/sdk', 'ANT_HOME': '/usr/share/ant', 'AZURE_EXTENSION_DIR': '/opt/az/azcliextensions', 'BOOTSTRAP_HASKELL_NONINTERACTIVE': '1', 'CHROMEWEBDRIVER': '/usr/local/share/chromedriver-linux64', 'CHROME_BIN': '/usr/bin/google-chrome', 'CI': 'true', 'DEBIAN_FRONTEND': 'noninteractive', 'DOCS_VERSION': '0.4.0', 'DOTNET_MULTILEVEL_LOOKUP': '0', 'DOTNET_NOLOGO': '1', 'DOTNET_SKIP_FIRST_TIME_EXPERIENCE': '1', 'EDGEWEBDRIVER': '/usr/local/share/edge_driver', 'ENABLE_RUNNER_TRACING': 'true', 'GECKOWEBDRIVER': '/usr/local/share/gecko_driver', 'GHCUP_INSTALL_BASE_PREFIX': '/usr/local', 'GITHUB_ACTION': '__run', 'GITHUB_ACTIONS': 'true', 'GITHUB_ACTION_REF': '', 'GITHUB_ACTION_REPOSITORY': '', 'GITHUB_ACTOR': 'PassionateBytes', 'GITHUB_ACTOR_ID': '184142773', 'GITHUB_API_URL': 'https://api.github.com', 'GITHUB_ARTIFACTS': '/home/runner/work/_temp/_runner_file_commands/artifacts_0f3662a6-8b35-4708-b69e-b0ce50f38737', 'GITHUB_ARTIFACTS_LIST': '/home/runner/work/_temp/_runner_file_commands/artifacts_list_0f3662a6-8b35-4708-b69e-b0ce50f38737', 'GITHUB_BASE_REF': '', 'GITHUB_ENV': '/home/runner/work/_temp/_runner_file_commands/set_env_0f3662a6-8b35-4708-b69e-b0ce50f38737', 'GITHUB_EVENT_NAME': 'push', 'GITHUB_EVENT_PATH': '/home/runner/work/_temp/_github_workflow/event.json', 'GITHUB_GRAPHQL_URL': 'https://api.github.com/graphql', 'GITHUB_HEAD_REF': '', 'GITHUB_JOB': 'build', 'GITHUB_OUTPUT': '/home/runner/work/_temp/_runner_file_commands/set_output_0f3662a6-8b35-4708-b69e-b0ce50f38737', 'GITHUB_PATH': '/home/runner/work/_temp/_runner_file_commands/add_path_0f3662a6-8b35-4708-b69e-b0ce50f38737', 'GITHUB_REF': 'refs/tags/v0.4.0', 'GITHUB_REF_NAME': 'v0.4.0', 'GITHUB_REF_PROTECTED': 'false', 'GITHUB_REF_TYPE': 'tag', 'GITHUB_REPOSITORY': 'PassionateBytes/phomemo-driver', 'GITHUB_REPOSITORY_ID': '1196991004', 'GITHUB_REPOSITORY_OWNER': 'PassionateBytes', 'GITHUB_REPOSITORY_OWNER_ID': '184142773', 'GITHUB_RETENTION_DAYS': '90', 'GITHUB_RUN_ATTEMPT': '1', 'GITHUB_RUN_ID': '42132868498', 'GITHUB_RUN_NUMBER': '35', 'GITHUB_SERVER_URL': 'https://github.com', 'GITHUB_SHA': 'a8f85160b85cc7aeaa626a8abf98083ff492fe94', 'GITHUB_STATE': '/home/runner/work/_temp/_runner_file_commands/save_state_0f3662a6-8b35-4708-b69e-b0ce50f38737', 'GITHUB_STEP_SUMMARY': '/home/runner/work/_temp/_runner_file_commands/step_summary_0f3662a6-8b35-4708-b69e-b0ce50f38737', 'GITHUB_TRIGGERING_ACTOR': 'PassionateBytes', 'GITHUB_WORKFLOW': 'Docs', 'GITHUB_WORKFLOW_REF': 'PassionateBytes/phomemo-driver/.github/workflows/docs.yml@refs/tags/v0.4.0', 'GITHUB_WORKFLOW_SHA': 'a8f85160b85cc7aeaa626a8abf98083ff492fe94', 'GITHUB_WORKSPACE': '/home/runner/work/phomemo-driver/phomemo-driver', 'GOROOT_1_24_X64': '/opt/hostedtoolcache/go/1.24.13/x64', 'GOROOT_1_25_X64': '/opt/hostedtoolcache/go/1.25.14/x64', 'GOROOT_1_26_X64': '/opt/hostedtoolcache/go/1.26.10/x64', 'GRADLE_HOME': '/usr/share/gradle-9.8.2', 'HCA_CLOUD_PROVIDER': 'azure', 'HOME': '/home/runner', 'HOMEBREW_CLEANUP_PERIODIC_FULL_DAYS': '3650', 'HOMEBREW_NO_AUTO_UPDATE': '1', 'INVOCATION_ID': '7ce7ac92393044e1b07e1bd0c2dc3b37', 'ImageOS': 'ubuntu26', 'ImageVersion': '20261101.186.1', 'JAVA_HOME': '/usr/lib/jvm/temurin-25-jdk-amd64', 'JAVA_HOME_11_X64': '/usr/lib/jvm/temurin-11-jdk-amd64', 'JAVA_HOME_17_X64': '/usr/lib/jvm/temurin-17-jdk-amd64', 'JAVA_HOME_21_X64': '/usr/lib/jvm/temurin-21-jdk-amd64', 'JAVA_HOME_25_X64': '/usr/lib/jvm/temurin-25-jdk-amd64', 'JOURNAL_STREAM': '10:15765', 'LANG': 'C.UTF-8', 'LOGNAME': 'runner', 'MEMORY_PRESSURE_WATCH': '/sys/fs/cgroup/system.slice/hosted-compute-agent.service/memory.pressure', 'MEMORY_PRESSURE_WRITE': 'c29tZSAyMDAwMDAgMjAwMDAwMAA=', 'NVM_DIR': '/home/runner/.nvm', 'PATH': '/home/runner/work/phomemo-driver/phomemo-driver/.venv/bin:/opt/hostedtoolcache/uv/0.13.7/x86_64:/home/runner/.local/bin:/snap/bin:/home/runner/.local/bin:/opt/pipx_bin:/home/runner/.cargo/bin:/home/runner/.config/composer/vendor/bin:/usr/local/.ghcup/bin:/home/runner/.dotnet/tools:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin', 'PIPX_BIN_DIR': '/opt/pipx_bin', 'PIPX_HOME': '/opt/pipx', 'POWERSHELL_DISTRIBUTION_CHANNEL': 'GitHub-Actions-Linux', 'PSModulePath': '/root/.local/share/powershell/Modules:/usr/local/share/powershell/Modules:/opt/microsoft/powershell/7/Modules:/usr/share/az_15.6.1', 'PWD': '/home/runner/work/phomemo-driver/phomemo-driver', 'RUNNER_ARCH': 'X64', 'RUNNER_ENVIRONMENT': 'github-hosted', 'RUNNER_NAME': 'GitHub Actions 1000001586', 'RUNNER_OS': 'Linux', 'RUNNER_TEMP': '/home/runner/work/_temp', 'RUNNER_TOOL_CACHE': '/opt/hostedtoolcache', 'RUNNER_TRACKING_ID': 'github_b95437ad-bf92-4fd1-8140-9b564a84b017', 'RUNNER_WORKSPACE': '/home/runner/work/phomemo-driver', 'SELENIUM_JAR_PATH': '/usr/share/java/selenium-server.jar', 'SGX_AESM_ADDR': '1', 'SHELL': '/bin/bash', 'SHLVL': '1', 'SWIFT_PATH': '/usr/share/swift/usr/bin', 'SYSTEMD_EXEC_PID': '2154', 'USER': 'runner', 'USE_BAZEL_FALLBACK_VERSION': 'silent:', 'UV': '/opt/hostedtoolcache/uv/0.13.7/x86_64/uv', 'UV_CACHE_DIR': '/home/runner/work/_temp/setup-uv-cache', 'UV_RUN_RECURSION_DEPTH': '1', 'VCPKG_INSTALLATION_ROOT': '/usr/local/share/vcpkg', 'VIRTUAL_ENV': '/home/runner/work/phomemo-driver/phomemo-driver/.venv', 'XDG_CONFIG_HOME': '/home/runner/.config', 'XDG_RUNTIME_DIR': '/run/user/1001', '_': '/opt/hostedtoolcache/uv/0.13.7/x86_64/uv', 'DOCUTILSCONFIG': '/home/runner/work/phomemo-driver/phomemo-driver/docs/docutils.conf'}), require_files=False)[source]#
Build the bridge configuration.
Later files override earlier ones;
PHOMEMO_BRIDGE_SOCKEToverrides the socket path from any file.- Parameters:
paths (list[Path] | None) – Files to read in override order;
Nonemeans the system file then the user’s XDG file.env (Mapping[str, str]) – Environment for the socket override and default locations.
require_files (bool) – Treat a missing file in
pathsas an error (for a path the user named explicitly).
- Returns:
The merged configuration.
- Return type:
BridgeConfig
Problems inside a file (unknown keys, wrong types, out-of-range values, a file that does not parse) are logged as warnings and the affected setting keeps its default.
- Raises:
ConfigError – If a file in
pathsis missing andrequire_filesis set.- Parameters:
paths (list[Path] | None)
env (Mapping[str, str])
require_files (bool)
- Return type:
BridgeConfig