NOTE: I still need to show the movements functions!
Universal Wireless CNC Pendant!
This handheld controller acts as a dedicated, real-time physical extension of your machine's klipper web interface
Features:
-
Real-Time Position Mirroring: Automatically polls and mirrors your machine's precise X, Y, Z positions multiple times per second.
-
Interactive Web Configuration Portal: Features a built-in captive network portal with a clean Web UI. Manage WiFi networks directly from your smartphone or PC.
-
Tactile Menu Navigation: Responsive menu browsing via an incremental rotary encoder with smooth acceleration logic.
-
Dedicated Emergency Overrides: Physical tactile buttons mapped directly to critical machine functions: Home (G28), Pause, Resume, and E-Stop (Emergency Stop /M112).
-
Crisp OLED Display: Clean, optimized layout using the U8g2 library for high-contrast viewing under workshop lighting conditions.
-
Two type C connectors: side one for esp32 in case you want to modify something and bottom one for charging
How It Works
-
Smart Network Onboarding: On first boot, if no WiFi is configured, the ESP32 hosts its own secure access point. Simply connect with your phone, and a polished dark-themed configuration page will automatically appear.
-
Adaptive Communication Engine: The pendant communicates directly with the Moonraker API on port 7125, utilizing an optimized JSON object polling mechanism to fetch coordinate states (gcode_move, toolhead) without taxing your Raspberry Pi. Movements are dispatched instantly via HTTP POST G-code scripts.
-
Asynchronous Architecture: Screen refreshes and button state routines run entirely independently of network calls, ensuring the UI remains perfectly fluid and never hitches during data transfers.
📦 Bill of Materials (BOM)
To build this project, you will need the following electronic components:
-
Microcontroller: ESP32 Devki v1 type C (30-pin variant).
-
Display: 128x128 OLED Display (e.g., Pimoroni SH1107 or equivalent I2C SSD1306/SH1107 display).
-
Navigation: EC11 Rotary Encoder with integrated push-button. ( I used B 20mm version )
-
Tactile Buttons: 8x MX switches (same as any generic mechanical keyboard)
-
Enclosure Hardware: M3x6 screws for securing the 3D-printed shell.
-
6x M3 heat inserts ( M3xL4xOD 4.2 )
-
2x 10x4mm magnets for securing the pendant on the base
-
1x tp4056 for changing the battery
-
2x 10k ohms resistors ( if you are using two batteries in parallel connection )
-
1x o 2x 18650 batteries
-
1x KCD11 switch
-
1x 22mm aluminum knob (or you can print it)
For the batteries I used jonnieZG's battery bracket
you just need to put the bracket on the battery and slide it in the slots that are on the case lid as shown in the pictures
For the MX switches I used low profile 3d printed ones but thats up to your taste
💻 Software & Flashing Instructions
-
Open the provided source code folder in the Arduino IDE.
-
Install the required libraries via the Library Manager:
-
U8g2 (by oliver)
-
ArduinoJson
-
ESPAsyncWebServer & AsyncTCP
-
AiEsp32RotaryEncoder
-
Adafruit_NeoPixel
-
-
Select your ESP32 model under Tools > Board, match your specific display pin configuration inside pendant.ino, and click Upload.
🔧 First-Time Configuration Guide
-
Power on the pendant. The screen will read "Config Portal Active" or display a hotspot prompt.
-
Open your smartphone or computer's WiFi settings and connect to the network named "Pendant-CNC".
-
A web page should open automatically. If it doesn't, navigate to http://192.168.4.1 in your browser.
-
Use the interface to select your WiFi network, input the password, and add your CNC with the respective name and local network IP address
-
Click Save & Reboot. The pendant will join your network, connect to your machine, and check mirroring coordinates
If you find any flaws on the code or the desing please let me know, there's the step file in case anyone wants to make any modification, keep in mind that my native language is spanish so there may be some words in spanish in the code
For my case I used 0 bottom layers and 5 top layers and 30% infill using Hilbert Curve to give it a more aesthetic look but you can experiment with more infills if you want
Cheers!
Tags
Model Source
