Skip to main content

acaia-lunar-ble

Python library for interacting with the Acaia Lunar coffee scale over Bluetooth Low Energy (BLE).

Built for specialty coffee enthusiasts who want to programmatically read weight data from their Acaia Lunar scale. Uses the bleak library for cross-platform BLE support (macOS, Linux, Windows).

Note: This library is specifically built for the Acaia Lunar model only — it does not support other Acaia scales (Acaia Pearl, Pyxis, etc.). It has been tested with the Lunar 2021 (Model AL008). Models AL009 and AL010 should work as well since they share the same BLE protocol, but have not been tested.

Demo Image

Demo Video

Features

  • Real-time weight streaming (stable and unstable readings)
  • Timer readback and control (start, stop, reset)
  • Tare command
  • Battery level and scale settings (units, auto-off, beep)
  • Button event notifications (tare, start, stop, reset pressed on scale)
  • Scan and discover nearby Acaia scales
  • Automatic heartbeat to maintain connection
  • Async/await API built on bleak
  • Context manager support for clean connect/disconnect

Installation

pip install acaia-lunar-ble

Quick Start

import asyncio
from acaia_lunar_ble import ScaleConnection


def on_weight(weight: float):
    print(f"Weight: {weight:.2f} g")


async def main():
    scale = ScaleConnection("YOUR-SCALE-ADDRESS", weight_callback=on_weight)

    if not await scale.connect():
        print("Failed to connect")
        return

    await asyncio.sleep(30)  # read weights for 30 seconds
    await scale.disconnect()


asyncio.run(main())

Finding Your Scale's Address

If you don't know your scale's BLE address, use the built-in discovery:

import asyncio
from acaia_lunar_ble import ScaleConnection


async def main():
    acaia_devices, all_devices = await ScaleConnection.discover()
    for d in acaia_devices:
        print(f"{d.name}: {d.address}")
    if not acaia_devices:
        print("No Acaia scales found. All nearby BLE devices:")
        for d in all_devices:
            print(f"  {d.name or '(unknown)'}: {d.address}")


asyncio.run(main())

Example Script

An interactive example script is included in examples/demo.py:

python examples/demo.py <SCALE-ADDRESS>

Interactive commands during the session:

Key Action
c Connect to the scale
d Disconnect from the scale
s Show connection status
t Tare (zero the scale)
1 Start timer
2 Stop timer
3 Reset timer
g Get settings (battery, units, auto-off, beep)
r Toggle raw BLE data stream logging
h Show commands
q Quit

Weight and timer readings update in real-time. Type a command letter and press Enter. Press q + Enter to quit, or Ctrl+C.

Context Manager

For automatic cleanup, use async with:

async with ScaleConnection(address, weight_callback=on_weight) as scale:
    await asyncio.sleep(60)  # stream weights for 60 seconds
# automatically disconnects when exiting the block

API Reference

ScaleConnection(address, *, ...)

Main class for interacting with the scale.

Constructor parameters:

  • address — BLE address (MAC or UUID) of the scale
  • weight_callback — called with each weight reading in grams (float)
  • timer_callback — called with timer value in seconds (float)
  • battery_callback — called with battery percentage (int, 0-100)
  • settings_callback — called with a ScaleSettings object (battery, units, auto-off, beep)
  • button_callback — called with button name (str): "tare", "start", "stop", or "reset"
  • notification_callback — called with every raw BLE notification payload (bytearray)

Methods

Method Description
await connect() Connect and start data streaming. Returns True on success.
await disconnect() Stop streaming and disconnect.
await scan_until_found() Block until the scale is found via BLE scan.
await ScaleConnection.discover(timeout=5.0) Scan for nearby Acaia scales. Returns (acaia_devices, all_devices).
await tare() Zero the scale.
await start_timer() Start the scale's built-in timer.
await stop_timer() Stop/pause the timer.
await reset_timer() Reset the timer to zero.
await get_settings() Request settings (response arrives via settings_callback).

Properties

Property Type Description
weight float | None Latest weight reading in grams.
timer float | None Latest timer value in seconds.
settings ScaleSettings | None Latest settings from the scale.
is_connected bool Whether the scale is currently connected.

ScaleSettings

Dataclass with fields: battery (int), units (str), auto_off_minutes (int), beep (bool).

decode_weight(data)

Standalone function to decode a BLE notification payload into a weight value in grams. Returns None if the data doesn't match the expected format.

Protocol Details

The Acaia Lunar uses a proprietary BLE protocol. Communication happens over two GATT characteristics:

  • Write characteristic (49535343-8841-43f4-a8d4-ecbe34729bb3) — used for sending commands (identify, notification request, heartbeat)
  • Notify characteristic (49535343-1e4d-4bd9-ba61-23c647249616) — streams weight and other data from the scale

The initialization sequence must follow this exact order:

  1. Subscribe to notifications
  2. Send IDENTIFY handshake
  3. Send NOTIFICATION_REQUEST to enable data streaming
  4. Start heartbeat loop (~3 second interval)

Requirements

  • Python 3.10+
  • Bluetooth Low Energy hardware
  • bleak (installed automatically)

License

MIT

Metadata

Release files for acaia-lunar-ble 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for acaia-lunar-ble 1.0.1
File Size Uploaded Provenance
acaia_lunar_ble-1.0.1.tar.gz 4.5 MB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for acaia-lunar-ble 1.0.1
File Interpreter ABI Platform
acaia_lunar_ble-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 4.5 MB

Release files / acaia_lunar_ble-1.0.1.tar.gz

Download URL acaia_lunar_ble-1.0.1.tar.gz
Size 4.5 MB
Tags Source
SHA-256 checksum
How to use checksums
0bbd04947457f39bc37e21c4b90def1b466887fab102dbc5291d60b6b34241e1
BLAKE2b-256 checksum
How to use checksums
16b19928c2ec607ba477360d769403ba04e8f815e874d2471ee3f5640aade86e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 4, 2026.

Transparency log

Release files / acaia_lunar_ble-1.0.1-py3-none-any.whl

Download URL acaia_lunar_ble-1.0.1-py3-none-any.whl
Size 10.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dbbdedf4070718047f850b9760f9f7f4b923ca88dbe1ea5cb6ba399db785832b
BLAKE2b-256 checksum
How to use checksums
2dca1599bffee579929083c210267560ce5842341f03ba32fa0daffb5c3e6677
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 4, 2026.

Transparency log

Security for acaia-lunar-ble 1.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for acaia_lunar_ble-1.0.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 4, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page