Date Range: June 2026 (initial setup through refinements)
Project Location: /home/lumenpnp/lumenpnp-addons
Primary Device: ESP32-WROOM-32 (dev board with CP2102 USB-UART on /dev/ttyUSB0)
Purpose: Fixed "in-bed" force/pressure sensor using load cells for OpenPnP Z-probing, nozzle tip calibration, board height measurement, etc. Replaces or supplements mechanical switches with a load-cell-based contact probe.
This file consolidates all decisions, hardware, wiring, firmware development, testing, web UI, OpenPnP integration, troubleshooting, and refinements discussed and implemented.
- Microcontroller: ESP32-WROOM-32 (generic dev board). USB serial via Silicon Labs CP2102 (VID:PID 10c4:ea60). Initially appeared as
/dev/ttyUSB0. - Load Cell Amplifier: Adafruit HX711 24-bit ADC breakout (product #5974). Important: split power supplies (VCC analog + VDD digital).
- Load Cells: Two 5kg bar-style load cells (Amazon B09VYSHW16 / ShangHJ generic). 4-wire: Red (E+), Black (E-), Green (A+), White (A-). Wired in parallel on Channel A for combined reading.
- Status LED: Built-in on ESP32 dev board (GPIO 2, defined as
STATUS_LED_PIN).
Mechanical Notes:
- Beam-style load cells: Fix one end rigidly (screw holes), apply downward force to the floating end (follow arrow/label on cell).
- Never press directly on the white rubber/silicone boot.
- Recommended: Mount two cells side-by-side; 3D-print a small platform/pad that the nozzle pushes in the center. Fixed in the LumenPnP bed.
- Adafruit VCC (analog / load cell excitation) → ESP32 5V (or VIN from USB; preferred for higher excitation voltage).
- Adafruit VDD (digital logic) → ESP32 3.3V.
- Adafruit GND → ESP32 GND.
Why split? VCC powers the load cell bridge and analog front-end. VDD sets the logic level for DATA/SCK (must match ESP32's 3.3V). Leave the VIO jumper on the back of the Adafruit board open.
- Adafruit DATA (DOUT) → ESP32 pin labeled D16 (GPIO 16).
- Adafruit SCK (CLK) → ESP32 pin labeled D17 (GPIO 17).
These are defined in include/pins.h:
#define HX711_DOUT_PIN 16
#define HX711_SCK_PIN 17
#define STATUS_LED_PIN 2Adafruit 6-pin terminal block (top edge):
- E+ ← Red from Cell 1 + Red from Cell 2 (tied together)
- E- ← Black from both cells
- A+ ← Green from both cells
- A- ← White from both cells
- B+ / B- ← Leave unconnected
Color confirmation (from Amazon kit + Adafruit guide):
- Red → E+
- Black → E-
- Green → A+
- White → A-
Tips:
- Twist same-color wires and insert into screw terminals (or use Wago/terminal strip for cleaner joints).
- Keep wires short; shield if noisy.
- Adafruit RATE switch: Start with L (10 SPS, less noise). H = 80 SPS (faster but noisier).
- Test one cell first, then add the second in parallel.
Pins.h also documents safe GPIOs and future expansion.
- Build System: PlatformIO (Arduino framework for ESP32).
- Main env:
esp32dev(production firmware). - Test env:
esp32dev_hx711_test(wiring verification only; excludes main.cpp viabuild_src_filter).
- Main env:
- Key Files:
platformio.ini— Two environments, upload/monitor speeds (921600 main, 115200 test for reliability), HX711 library (bogde/HX711@^0.7.5).include/pins.h— Pin definitions + documentation.src/main.cpp— Production code (G-code + WiFi web server).src/hx711_test.cpp— Standalone test firmware.README.md— Comprehensive user docs (wiring, OpenPnP, calibration, web UI).PRESSURE_SENSOR_MEMORY.md— This file (implementation history).
- Git: Initialized in
/home/lumenpnp/lumenpnp-addons. Multiple commits tracking evolution (wiring docs, WiFi addition, ready-detection fixes, G-code tester, mDNS, etc.). - pio path (when
pionot in PATH):/home/lumenpnp/.platformio/penv/bin/pio
Build/Flash Commands (examples):
cd /home/lumenpnp/lumenpnp-addons
# Main production firmware (G-code + web)
pio run -e esp32dev -t upload --upload-port /dev/ttyUSB0
# Test firmware only (for wiring verification)
pio run -e esp32dev_hx711_test -t upload --upload-port /dev/ttyUSB0
# Monitor
pio device monitor --port /dev/ttyUSB0 --baud 115200Implemented in handleGcode() + performProbe().
Supported commands (minimal but functional for probing/actuators):
M115— Firmware info + capabilities (name, version, calibration factor, trigger threshold).M114— Current load (grams + raw ADC), threshold, armed/triggered state.M600— Tare (zero) the scale.M600 S<grams>sets trigger threshold on the fly.G38.2/G38.3— Arm probe and wait for contact (load >= threshold). On trigger: prints "Probe triggered!",PRB:0.000,ok. Blocks (with serial draining for aborts) up to 30s timeout.M999/M112— Abort/reset probe state.- Unknown commands →
ok ; unknown: ...(OpenPnP-friendly).
Probe Logic:
- Non-blocking serial accumulation in
loop(). - Armed state checked continuously; triggers on weight threshold.
- Serial draining inside
performProbe()for abort commands. - LED feedback (solid when armed, blink on trigger).
Improvements Made:
- Switched from
scale.is_ready()toscale.wait_ready_timeout(100-200)in reads, status, tare, and probe. This fixed frequent false "HX711 not ready" messages (library's quick pin check is unreliable on ESP32 due to WiFi interrupts/timing). Actual reads viaread_average()/get_units()still succeeded and showed correct changing values on pressure.
Added later for live monitoring and control (no need for constant serial monitor).
- Credentials: Stored in NVS via
M710 S"<ssid>" P"<password>"(not hardcoded). Uses DHCP (no static IP). Connects inWIFI_STAmode. - mDNS:
lumen-probe.local(viaESPmDNS). - IP: DHCP-assigned; printed on boot via serial.
- Endpoints (served via
WebServeron port 80):/— Full self-contained HTML/JS page (Tailwind CDN for styling)./status— JSON:grams,raw,threshold,armed,triggered,hx711_ready,ip,uptime./tare(POST) — CallstareScale()./set?g=XX— Live threshold change./send?cmd=XXX— TriggershandleGcode()(G-code tester). Returns "Sent: XXX". Actual detailed responses go to USB serial.
Web Page Features (live-updating every ~450ms):
- Large live grams display + raw ADC.
- Force bar (fills relative to threshold; turns red on trigger).
- Status cards (Armed / Triggered / HX711 ready).
- Controls: Tare button, threshold input + set, "Manually Arm Probe (test)".
- G-code tester: Input box + Send (logs "Sent" + responses). Great for experimenting with M114/M600/G38.2 while watching live status.
- Uptime + IP.
Boot Messages (via Serial):
- HX711 init status.
- WiFi connection progress + final IP + mDNS + "Web server started."
- "Ready for OpenPnP GcodeDriver."
Loop:
- Serial G-code handling.
- Probe state machine.
server.handleClient()for web.- Small
delay(2)for watchdog/WiFi.
Standalone env for initial wiring verification (before trusting production G-code).
- Same pins via
pins.h. - Continuous readings (Raw + Grams with current cal factor).
- Serial commands:
t(tare),c <val>(set cal factor),?(help). - LED feedback.
- "HX711 not ready" warnings (improved with
wait_ready_timeoutin later versions). - Prints expected wiring on boot.
Usage (as documented):
pio run -e esp32dev_hx711_test -t upload --upload-port /dev/ttyUSB0
pio device monitor --port /dev/ttyUSB0 --baud 115200Test with M114-style output and physical pressure. Once stable, switch back to main env.
The device is designed as a serial G-code peripheral (not on the main Marlin bus).
- Machine Setup → Drivers → New GcodeDriver.
- Name: e.g. "HX711 Bed Probe".
- Port: ESP32 serial (e.g.
/dev/ttyUSB0). - Baud: 115200.
- Command confirm regex:
^ok(or^ok.*). - Connect wait: 1500–2000 ms (ESP32 resets on port open).
- Units: Millimeters.
- Leave other settings default.
- Add Actuator (e.g. name "BedZProbe" or "ForceProbe").
- Driver: the GcodeDriver above.
- Read / Actuate Command:
G38.2 Z-50 F100(Z/F largely ignored; firmware just waits for force threshold). - Optional: Before command
M600(auto-tare when pad is clear).
- Nozzle Tip Calibration: Assign the actuator for contact detection during "Measure Nozzle Tip". OpenPnP lowers nozzle, sends G38.2, waits for "ok" (trigger), records machine Z.
- Board / panel height probing.
- Feeder pickup height.
- Custom scripts / macros.
Responses on Trigger (useful for parsing):
Probe triggered!
PRB:0.000
ok
Maintenance Commands (can be sent from OpenPnP or web tester):
M600— Tare before a session.M114— Query current state.M600 S25— Adjust sensitivity (default ~30g; tune per mechanical setup).M999— Abort.
Tips:
- Use the web page's G-code tester for quick validation of commands/responses while configuring OpenPnP.
- Clear the pad and tare (
M600) before probing sessions. - The "ok" after G38.2 signals contact; OpenPnP captures the machine position at that moment.
- Threshold and calibration are in RAM (re-tare / re-set on power cycle or via commands).
Full step-by-step was added to README during development.
- Nothing on the pad → send
M600(tare). - Place known weight (e.g. 100g, 200g) → note
M114reading. - In
src/main.cpp(or via web /M600 Sxxfor threshold):constexpr float DEFAULT_CALIBRATION_FACTOR = -1000.0f; // Tune sign & magnitude constexpr float DEFAULT_TRIGGER_THRESHOLD_G = 30.0f;
- Formula:
new_factor = (reading_with_known_weight / actual_grams) * current_factor. - Re-flash or use runtime commands. Repeat until
M114is accurate. - Test
G38.2while pressing the pad (should trigger within timeout).
Runtime Tuning:
M600 S42.5(from serial or web tester) changes threshold without re-flash.- Web page allows live threshold changes + tare.
-
"HX711 not ready - check connections" but values still change on pressure:
- Root cause:
scale.is_ready()is a lightweightdigitalRead(DOUT)that can falsely return false due to ESP32 WiFi interrupts, timing, 10/80 SPS rate, or sampling between conversions. Actualread_average()/get_units()still succeed. - Fix implemented: Replaced strict
is_ready()checks withscale.wait_ready_timeout(100-200)inreadWeightGrams(),reportStatus(),tareScale(),performProbe(), web JSON, and test firmware loop. This is the library-recommended reliable pattern. "not ready" messages now only appear for real problems. - LED still provides visual confirmation.
- Root cause:
-
Upload issues (early): Used safer
upload_speed = 115200in test env; main uses higher. Hold BOOT/EN buttons if needed on some boards. Crystal freq warnings seen but not fatal. -
No /dev/ttyUSB0: Device re-enumeration (check
ls /dev/ttyUSB*,lsusb). ESP was sometimes on USB1 or disappeared until re-plugged. -
WiFi / Web not appearing: Confirm SSID/password exact match (
M710). Watch serial on boot for connection messages + IP. Must be on the same LAN as the addon to reach the page. mDNS helps (lumen-probe.local). -
False triggers / no triggers: Adjust threshold (
M600 Sxxor web). Ensure mechanical mounting is solid (no side loads/twisting). Tare when clear. -
Web page not updating live: JS polls
/statusevery ~450ms. Works over WiFi from same network. -
Serial noise on capture: Common in tool environments (TTY issues post-reset). Real firmware output is clean when using
pio device monitor. -
Power: Always use proper split (5V VCC, 3.3V VDD). HX711 likes 5V excitation when possible.
- Initial: Empty dir → PlatformIO + ESP32 + basic HX711 skeleton + G-code parser (M115/M114/M600/G38.x) + pins.h + README wiring.
- Wiring refinement: Identified Adafruit split supplies (VCC/VDD), parallel load cells, exact D16/D17 mapping for boards using D## labels. Updated docs.
- Test firmware: Created dedicated env +
hx711_test.cppfor safe verification. - OpenPnP docs: Added detailed GcodeDriver + actuator instructions to README.
- WiFi + Web Diagnostics (major addition): Added WiFi (hardcoded creds), WebServer, JSON status, self-contained HTML/JS page with live updates, controls, and G-code tester (
/send). Boot prints IP + mDNS.server.handleClient()in loop. - "Not ready" fix: Switched to
wait_ready_timeoutacross all read/status paths (both main and test). Re-flashed and verified cleaner output. - G-code tester validation: Tested via direct HTTP (
/send?cmd=M114,M600 S42.5) + serial. Confirmed threshold changes and status updates live on the page. Responses go to serial (as designed). - mDNS: Added
ESPmDNSforlumen-probe.local. - Documentation: Extensive README updates (wiring, OpenPnP, web UI, calibration). This MEMORY.md created as consolidated reference.
- Flashes: Multiple successful uploads (main + test). Serial captures used to verify boot, WiFi, DHCP IP, and live pressure response.
- Git: Clean history with descriptive commits (e.g., "Correct power wiring...", "Add dedicated HX711 wiring test firmware", "Improve D## pin explanation", "Configure WiFi...", "G-code readiness + live diagnostics webpage").
Diagnostics URL: Check serial on boot for the DHCP IP, or use http://lumen-probe.local from the same LAN.
- Firmware flashed and running with WiFi, web UI, G-code over USB, and improved ready detection.
- Web page live and responsive (live grams/raw, controls, G-code tester).
- OpenPnP GcodeDriver + actuator ready (G38.2 for contact, M600 for tare).
- Both load cells in parallel responding to pressure (verified via test firmware and web).
- Threshold was set to 42.5g in one test session.
- HX711 consistently reports ready after fixes.
Recommended Workflow:
- Power on → watch serial for "WiFi connected", IP, "Web server started".
- Open web page (same WiFi) → verify live readings, tare, test G-code.
- In OpenPnP: configure driver/actuator as documented.
- Tare (
M600) with pad clear before sessions. - Use web G-code tester or serial for quick experiments.
Future / Optional:
- Persistent settings (Preferences / NVS for cal factor + threshold across reboots).
- Better non-blocking HX711 (switch to
HX711_ADClib if needed). - More sensors on same ESP32 (I2C bus).
- Richer web G-code log (capture recent serial output).
- mDNS improvements or captive portal.
- Full user docs:
README.md(wiring diagrams, OpenPnP steps, calibration formula, web UI screenshots/descriptions). - Pins:
include/pins.h. - Production code:
src/main.cpp(G-code + web). - Test code:
src/hx711_test.cpp. - Build config:
platformio.ini. - This file:
PRESSURE_SENSOR_MEMORY.md.
To re-flash or test:
pio run -e esp32dev -t upload --upload-port /dev/ttyUSB0
# or the test envAll commands, wiring, and code are in the repo. This memory file captures the why and evolution behind the final state.
End of Memory File. Rebuild or extend as needed for future sessions (e.g., laser probe additions were discussed separately after this pressure sensor work was complete).
If re-visiting: Always verify current IP via serial, test with web G-code tester first, and tare before OpenPnP probing.