Documentation

Developer reference for Puffco Peak Pro and Proxy BLE telemetry and control.

Python 3.9–3.12 Bleak GATT Lorax VFS MIT License

Introduction

puffco-py is a standalone, lightweight, asynchronous Python library for communicating with Puffco Peak Pro (V1, V2, Limited Editions) and Puffco Proxy vaporizers using Bluetooth Low Energy (BLE).

Modern Puffco devices use a proprietary firmware protocol called the Lorax Virtual File System (VFS). Rather than using fixed GATT characteristics for every sensor, Puffco multiplexes virtual file paths over a single write/notify characteristic pair. puffco-py implements this protocol natively, providing:

  • Low latency streaming — Adaptive polling at up to ~16 FPS (60ms) during active heating sessions.
  • Cryptographic authentication — Automatically solves the SHA-256 access seed challenge required by modern firmware.
  • Desktop GUI friendly — Dedicated background-worker thread client (ThreadedPuffcoClient) for Tkinter, PyQt, and macOS status bar widgets.
  • Hardware telemetry — Live bowl temperature, battery %, charging status, chamber detection (3D, 3DXL, Proxy), and lifetime dab counter.

Installation

Requires Python 3.9 or higher. Install from PyPI or build from source.

Standard Install (PyPI)

bash
pip install puffco-py

Optional Extras

Include CLI formatting and macOS menu bar widget dependencies:

bash
pip install "puffco-py[cli,gui]"

From Source

bash
git clone https://github.com/SoyMilkIsOk/puffco-py.git
cd puffco-py
pip install -e .

Hardware & Platform Support

Device Chambers Firmware Status
Peak Pro V2 3DXL, Standard 3D v5.0–v5.4.x ✓ Supported
Peak Pro V1 Standard 3D, Ceramic v4.x, v5.x ✓ Supported
Puffco Proxy Proxy 3D Chamber All production ✓ Supported
ℹ️
BLE Permissions:
macOS: Enable Bluetooth for your terminal in System Settings > Privacy & Security > Bluetooth.
Linux: Ensure bluez is installed. You may need to add your user to the bluetooth group.

Async Python Quickstart

PuffcoClient is an async context manager powered by asyncio and bleak. It auto-discovers the nearest device, authenticates, and starts telemetry.

python
import asyncio
from puffco_py import PuffcoClient

async def main():
    async with PuffcoClient() as client:
        print(f"Connected to: {client.telemetry.device_name}")
        print(f"Chamber: {client.telemetry.chamber_name} | Battery: {client.telemetry.battery_pct}%")

        def on_telemetry(t):
            print(f"\rTemp: {t.live_temp_f:.1f}°F | State: {t.state_name}", end="")

        client.add_telemetry_listener(on_telemetry)
        await client.start_telemetry_stream()
        await asyncio.sleep(15)

asyncio.run(main())

Threaded / GUI Quickstart

For desktop GUIs (Tkinter, PyQt, PySide) or synchronous scripts, use ThreadedPuffcoClient. It runs the async BLE event loop on a background thread and exposes simple synchronous methods:

python
import time
from puffco_py import ThreadedPuffcoClient

client = ThreadedPuffcoClient()
client.add_telemetry_listener(lambda t: print(f"Live Temp: {t.live_temp_f:.1f}°F"))

client.start()

if client.wait_connected(timeout=10.0):
    print(client.telemetry.summary())

    client.set_profile(slot=1)
    client.start_session()
    time.sleep(10)
    client.boost()
    time.sleep(10)
    client.stop_session()

client.stop()

CLI Commands

The package includes an out-of-the-box CLI utility named puffco-py:

Command Options Description
puffco-py scan -t, --timeout <sec> Scan BLE advertisements for nearby Puffco devices.
puffco-py monitor --mac <addr> Live stream an interactive terminal HUD with temp, battery, and state.
puffco-py info --mac <addr> Dump hardware serial, firmware version, dab count, and profiles.
puffco-py sesh <action> start, stop, boost Send immediate heating commands to the connected device.
💡
If multiple devices are in range, supply --mac AA:BB:CC:DD:EE:FF to target a specific unit.

macOS Menu Bar Widget

A native macOS status bar app is provided in examples/04_mac_menu_widget.py (powered by rumps):

bash
pip install "puffco-py[gui]"
python3 examples/04_mac_menu_widget.py

The widget displays live bowl temperature in your menu bar and provides one-click dropdown actions to start, boost, or abort sessions.

Features

  • Lorax VFS Protocol — Native support for Puffco firmware using Lorax Virtual File System sequence multiplexing and SHA-256 challenge-response authentication.
  • Sub-100ms Streaming — Adaptive polling engine streams ~16 FPS (60ms) during active heating and throttles to 250ms when idle.
  • Thread-Safe & GUI ReadyThreadedPuffcoClient for synchronous UI toolkits (Tkinter, PyQt, PySide) without blocking dispatch threads.
  • macOS Status Bar Widget — Ready-to-run native menu bar app powered by rumps, showing live temps and one-click session triggers.
  • Auto-Discovery — Scans BLE advertisements and filters nearest devices by manufacturer OUI and Lorax GATT UUIDs.
  • Full Session Control — Start sessions, abort, trigger heat boosts, change profiles, set temperatures, and toggle stealth mode.

Python API Reference

PuffcoClient Methods

Method Return Description
async connect(timeout=10.0) bool Connects via Bleak GATT and solves the Lorax SHA-256 access seed challenge.
async disconnect() None Gracefully terminates GATT connection and stops polling.
async start_session() None Initiates a heating session using the active profile.
async stop_session() None Aborts an active heating session immediately.
async boost() None Applies heat boost (+15s duration and +10°F).
async set_profile(slot: int) None Switches active profile slot (0–3).
async set_stealth_mode(enabled: bool) None Toggles device mood lights on or off.
add_telemetry_listener(callback) None Registers a callback(telemetry) called on state changes.

Telemetry Model

Accessible via client.telemetry:

Property Type Description
live_temp_f float Current real-time bowl temperature in °F.
target_temp_f float Target temperature of the active profile.
battery_pct int Battery state of charge (0–100%).
is_charging bool True if plugged in via USB-C or on Qi dock.
chamber_name str Detected chamber: "3D", "3DXL", "Proxy", or "None".
operating_state Enum IDLE, HEAT_PREHEAT, HEAT_ACTIVE, HEAT_FADE.
lifetime_dabs int Total completed sessions stored in hardware memory.

Lorax VFS Protocol

Puffco firmware implements a sequence-multiplexed file system over BLE:

GATT Entity UUID Properties
Service e276967f-ea8a-478a-a92e-d78f5dd15dd5 Primary Lorax BLE Service
Command 60133d5c-5727-4f2c-9697-d842c5292a3c Write Without Response
Reply 8dc5ec05-8f7d-45ad-99db-3fbde65dbd9c Notify / Indicate

VFS Paths

  • /p/app/stat/id — Operating state byte (0=Idle, 1=Preheat, 2=Sesh, 3=Fade)
  • /p/app/htr/temp — Chamber temperature sensor reading
  • /p/app/mc — Mode control (0x07=Start, 0x08=Stop, 0x09=Boost)
  • /p/bat/soc — Battery state of charge percentage
  • /p/app/odom/0/nc — Lifetime completed dabs counter

Authentication Flow

  1. GATT Connection — Bleak discovers device via Lorax service UUID and establishes an MTU-negotiated link.
  2. Seed Challenge — Client sends opcode 0x00 (GET_ACCESS_SEED) to request a 16-byte random seed.
  3. SHA-256 Auth — Client computes SHA256(MasterKey + Seed)[:16] and sends opcode 0x01 (UNLOCK_ACCESS).
  4. Stream Telemetry — Client polls VFS paths for live temperature, state, and battery level.

Troubleshooting

Device not found during scan

Ensure your Puffco is powered on and within range (~5–10 feet). If connected to the official Puffco Connect app, BLE will reject secondary connections. Disconnect the app and re-run puffco-py scan.

Permission denied on macOS

In macOS Ventura/Sonoma/Sequoia, terminal apps need explicit Bluetooth authorization. Go to System Settings > Privacy & Security > Bluetooth and toggle your terminal app ON.

Running tests

bash
python3 -m unittest discover tests/