Documentation
Developer reference for Puffco Peak Pro and Proxy BLE telemetry and control.
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)
pip install puffco-py
Optional Extras
Include CLI formatting and macOS menu bar widget dependencies:
pip install "puffco-py[cli,gui]"
From Source
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 |
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.
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:
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. |
--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):
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 Ready —
ThreadedPuffcoClientfor 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
- GATT Connection — Bleak discovers device via Lorax service UUID and establishes an MTU-negotiated link.
- Seed Challenge — Client sends opcode
0x00(GET_ACCESS_SEED) to request a 16-byte random seed. - SHA-256 Auth — Client computes
SHA256(MasterKey + Seed)[:16]and sends opcode0x01(UNLOCK_ACCESS). - 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
python3 -m unittest discover tests/