Catalog PyPI
PACKAGE EXPLORERView in registry

acaia-lunar-ble

PyPI

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

acaiablebleakbluetoothcoffeelunarscalespecialty-coffee
Versions collected1
Direct dependencies1From release 1.0.1
Last observed20 Oct, 17:51 UTC

README

Version 1.0.1 documentation

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:

KeyAction
cConnect to the scale
dDisconnect from the scale
sShow connection status
tTare (zero the scale)
1Start timer
2Stop timer
3Reset timer
gGet settings (battery, units, auto-off, beep)
rToggle raw BLE data stream logging
hShow commands
qQuit

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

MethodDescription
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

PropertyTypeDescription
weightfloat | NoneLatest weight reading in grams.
timerfloat | NoneLatest timer value in seconds.
settingsScaleSettings | NoneLatest settings from the scale.
is_connectedboolWhether 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

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
1.0.14 Apr 20261

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
beat843796/acaia-lunar-ble

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 17:51 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:ae331c1a16b1f51f181fa1d34b52477619a8321a654d22b37d1972cebe36a693