Welcome! This repository contains ankerctl, a command-line interface and web UI for monitoring, controlling, and interfacing with AnkerMake M5 3D printers.
Note: While changes are tested carefully, bugs still happen. If you run into one, please open a GitHub Issue.
This repository continues the work started by the original Ankermgmt/ankermake-m5-protocol team. Thanks to the original authors for the reverse engineering work and the foundation this fork builds on.
The ankerctl program uses libflagship, a library for communicating with the multiple protocols required to connect to an AnkerMake M5 printer. libflagship is maintained in this repo under libflagship/.
- Print directly from slicers such as PrusaSlicer, SuperSlicer, OrcaSlicer, Bambu Studio, and other compatible slicers that can submit jobs to a custom print host.
- Connect to AnkerMake M5 printers and AnkerMake cloud APIs without relying on closed-source Anker software.
- Multi-printer support with per-printer status, controls, history, media views, and settings.
- Send raw G-code commands to the printer and view responses in real time.
- Low-level access to MQTT, PPPP, and HTTPS APIs for debugging and advanced integrations.
- Upload G-code to the printer, start prints from compatible printer storage entries, and reprint compatible archived jobs from history.
- View printer storage, USB storage, and print history with thumbnail previews when available.
- Automatic print history backed by SQLite, including filename, timestamps, duration, result, thumbnails, and reprint availability.
- Automatic timelapse capture during prints, including pause, resume, stop, partial-save-on-failure behavior, per-printer camera source selection (
follow, printer, or external), and MP4 assembly at print end. Requiresffmpeg. - Dedicated Snapshots page for timelapse frames and manual snapshots, including preview, download, and delete actions.
- Stream the built-in printer camera to your computer, with support for optional external camera feeds and a camera setup page.
- Manual snapshot capture from the Home page, with snapshots saved into the Snapshots gallery.
- Live ankerctl console viewer on the Home page, with recent history and live updates.
- Filament status indicators and filament-change awareness in printer status.
- Safer filament management tools, including validation for blank profile names, clearer in-page error handling, and protection against unsafe legacy filament-apply actions during active prints.
- Sticky printer alerts and notifications, including support for events from printers other than the currently selected one.
- Push notifications via Apprise for print start, finish, failure, upload, and progress, with optional image attachments.
- Home Assistant MQTT Discovery integration for printer state, temperatures, progress, and light control.
- Optional API key protection for write operations and sensitive API endpoints.
- Debug tab (enable with
ANKERCTL_DEV_MODE=true) with a state inspector, service health panel, event simulation, and log viewer. - Bed Level Map (Setup -> Tools) that reads the 7x7 bilinear compensation grid via
M420 V, renders it as a heatmap, and supports before/after comparison snapshots. - Improved account import and login flows:
- CLI import supports legacy
login.json/user_infofiles and the newer eufyMake Studio Windows WebView LevelDB cache (.ldbfiles). - Windows autodetect prefers the newest usable slicer session record instead of older stale cache blobs.
- Import can recover certain truncated WebView auth-token cases by validating candidate prefixes against the API.
- The web UI includes a one-click Import From eufyMake Studio flow plus manual upload fallback.
- The Setup page shows clear success and failure banners for both import and direct login flows.
- Manual login trims inputs, normalizes country codes, stays on-page on failure, and prevents duplicate submits while fetching.
- CLI import supports legacy
- Includes a downloadable Windows launcher.
Let us know what you want to see next. Pull requests are always welcome.
Choose one installation method:
- Install from Git - recommended
- Install from Docker
Suggested order of operations:
- Choose an installation method.
- Complete the install steps for that method.
- Import your AnkerMake account configuration or sign in directly.
- Start
ankerctlfrom the CLI or launch the web server.
Note Minimum supported Python version is 3.10.
Warning Docker installation currently works on Linux only.
There are now three supported ways to get account and printer data into ankerctl:
- CLI import from a cached AnkerMake/eufyMake session
- Web UI import from an uploaded file or from an open eufyMake Studio session on the same machine
- Direct login with your email and password
Open a terminal in the ankerctl folder and run:
python3 ankerctl.py config importWhen no filename is provided, ankerctl tries to auto-detect a supported cached login source.
- Legacy
login.json - Legacy
user_info - Newer eufyMake Studio Windows WebView LevelDB cache files (
.ldb)
On modern Windows installs, the importer can scan the LevelDB session cache and select a usable eufyMake Studio session automatically.
Important When importing from the newer eufyMake Studio cache on Windows, keep eufyMake Studio open and signed in while you run the import.
Auto-detect supported cache files
python3 ankerctl.py config importWindows legacy cache example
python3 ankerctl.py config import %APPDATA%\Roaming\eufyMake Studio Profile\cache\offline\user_infoWindows newer eufyMake Studio LevelDB folder example
python3 ankerctl.py config import %LOCALAPPDATA%\eufyMake Studio Profile\EBWebView\Default\Local Storage\leveldb\000123.ldbmacOS example
./ankerctl.py config import $HOME/Library/Application Support/eufyMake Studio Profile\EBWebView\Default\Local Storage\leveldb\000123.ldbLinux/Wine example
./ankerctl.py config import ~/.wine/drive_c/users/username/AppData/Roaming/eufyMake Studio Profile/EBWebView/Default/Local Storage/leveldb/000123.ldbType ankerctl.py config import -h for all options.
To learn more about the underlying account and printer data used during import, see:
[*] Loading cache..
[*] Initializing API..
[*] Requesting profile data..
[*] Requesting printer list..
[*] Requesting pppp keys..
[*] Adding printer [AK7ABC0123401234]
[*] Finished importAfter import, your configuration is stored in ankerctl's managed config file. You can inspect the saved account and printer info with:
./ankerctl.py config show
[*] Account:
user_id: 01234567890abcdef012...<REDACTED>
email: bob@example.org
region: eu
[*] Printers:
sn: AK7ABC0123401234
duid: EUPRAKM-001234-ABCDEThe web UI supports two import paths in Setup -> Account:
Use Import From eufyMake Studio.
This is the easiest option on supported systems because the server will:
- look for the correct slicer cache automatically
- choose the newest usable session record
- import the account and printer data for you
- show a clear success or failure banner after reload
Important Keep eufyMake Studio open and signed in before using this button.
If one-click import is unavailable or fails, you can still upload a supported file manually from Setup -> Account.
Supported upload sources include:
login.jsonuser_info000123.ldb- supported eufyMake Studio cache files such as
.ldb
The Setup page now refers to this more accurately as a login file or slicer cache, not only a login file.
A successful import shows a green banner similar to:
Configuration imported from open eufyMake Studio for your@email.com with 2 printers.
A failed import shows a red banner with the actual reason.
You can also fetch account and printer data directly from the AnkerMake servers.
./ankerctl.py config login DEYou will be prompted for your email and password. If AnkerMake requires a CAPTCHA, the CLI will open it in your browser and ask for the answer.
In Setup -> Account, use the manual login form.
Recent improvements to this flow include:
- trimmed email, country, and CAPTCHA fields
- automatic uppercase normalization for country codes
- better inline error handling without bouncing away from the page
- a disabled Fetch button with spinner while the request is running
- clearer success and failure banners
A successful direct login shows a green banner similar to:
Configuration fetched from AnkerMake server for your@email.com with 2 printers.
A failed login stays on the same page and shows the actual error in red.
Note The cached login info contains sensitive details. In particular, the
user_idfield is used when connecting to MQTT servers and effectively behaves like a password. For that reason the value is redacted when printed to the screen.
Once import or login succeeds, ankerctl is ready to use.
Start the web server from the folder where you installed ankerctl. The web server must be running whenever you want to:
- use the web interface
- send jobs from a slicer
- use browser-based controls, history, timelapse, snapshots, or camera pages
# Build the image (match UID/GID to your host user)
docker build -t django01982/ankerctl:local --build-arg UID=$(id -u) --build-arg GID=$(id -g) .
# Copy .env.example to .env and adjust values, then start
cp .env.example .env
docker compose up./ankerctl.py webserver runThen open:
http://localhost:4470
in a browser on the same machine.
Important If account configuration has not been imported yet, go to Setup -> Account and either:
- click Import From eufyMake Studio
- upload a supported login file or slicer cache
- or sign in directly with email and password
ankerctl can receive jobs from slicers that support a custom print host / HTTP upload workflow.
Tested slicers include:
- PrusaSlicer
- SuperSlicer
- OrcaSlicer
- Bambu Studio
The web server must be running before the slicer can send a job.
At the moment, slicer-hosted upload is intended for immediate use, so the common workflow is:
- Send and Print to upload and start the print right away
Additional slicer-specific instructions are available in the web interface Instructions page.
ankerctl supports optional API key authentication.
When enabled:
- write operations and sensitive API endpoints require the key
- the normal read-only web UI remains viewable
- slicers must send the same key if they are uploading through the host interface
# Generate a random API key
./ankerctl.py config set-password
# Or set a specific key
./ankerctl.py config set-password my-secret-key
# Remove key (disable authentication)
./ankerctl.py config remove-password# In .env (see .env.example)
ANKERCTL_API_KEY=my-secret-key- Slicer: enter the key in the slicer's API Key field so it is sent as the
X-Api-Keyheader - Browser: append
?apikey=your-keyto the URL once; a session cookie is set automatically - No key set: authentication stays disabled for backward compatibility
ankerctl is configured through environment variables. For Docker deployments, copy .env.example to .env, adjust the values, and let Docker Compose load them automatically.
| Variable | Default | Description |
|---|---|---|
| Server | ||
FLASK_HOST |
127.0.0.1 |
IP address the web server binds to |
FLASK_PORT |
4470 |
Port the web server listens on |
FLASK_SECRET_KEY |
(auto-generated) | Session cookie secret; set this explicitly if you want it to persist across restarts |
PRINTER_INDEX |
0 |
Select printer by index when multiple printers are configured |
| Upload | ||
UPLOAD_MAX_MB |
512 |
Maximum upload file size in MB |
UPLOAD_RATE_MBPS |
10 |
Upload speed to printer in Mbit/s (choices: 5, 10, 25, 50, 100) |
| Security | ||
ANKERCTL_API_KEY |
(unset) | API key for write-operation authentication |
| Feature Flags | ||
ANKERCTL_DEV_MODE |
false |
Enable the Debug tab and /api/debug/* endpoints |
ANKERCTL_LOG_DIR |
(unset) | Directory for log files; enables file logging when set |
| Apprise Notifications | ||
APPRISE_ENABLED |
false |
Enable Apprise notifications |
APPRISE_SERVER_URL |
(unset) | Apprise API server URL |
APPRISE_KEY |
(unset) | Apprise notification key/ID |
APPRISE_TAG |
(unset) | Apprise tag filter |
APPRISE_EVENT_PRINT_STARTED |
true |
Notify when a print starts |
APPRISE_EVENT_PRINT_FINISHED |
true |
Notify when a print finishes |
APPRISE_EVENT_PRINT_FAILED |
true |
Notify when a print fails |
APPRISE_EVENT_GCODE_UPLOADED |
true |
Notify when G-code is uploaded |
APPRISE_EVENT_PRINT_PROGRESS |
true |
Notify on progress updates |
APPRISE_PROGRESS_INTERVAL |
25 |
Progress notification interval (%) |
APPRISE_PROGRESS_INCLUDE_IMAGE |
false |
Attach a camera snapshot to progress notifications |
APPRISE_PROGRESS_MAX |
0 |
Override progress scale (0 = auto) |
APPRISE_SNAPSHOT_QUALITY |
hd |
Snapshot quality: sd, hd, or fhd (1920x1080) |
APPRISE_SNAPSHOT_FALLBACK |
true |
Use the G-code preview if live capture fails |
APPRISE_SNAPSHOT_LIGHT |
false |
Turn on the printer light for the snapshot |
| Print History | ||
PRINT_HISTORY_RETENTION_DAYS |
90 |
Number of days to keep history entries |
PRINT_HISTORY_MAX_ENTRIES |
500 |
Maximum number of history entries to keep |
| Timelapse | ||
TIMELAPSE_ENABLED |
false |
Enable automatic timelapse capture (requires ffmpeg) |
TIMELAPSE_INTERVAL_SEC |
30 |
Seconds between captures |
TIMELAPSE_MAX_VIDEOS |
10 |
Maximum number of timelapse videos to keep |
TIMELAPSE_SAVE_PERSISTENT |
true |
Save assembled videos persistently |
TIMELAPSE_CAPTURES_DIR |
/captures |
Directory used for timelapse video storage |
TIMELAPSE_LIGHT |
(unset) | Timelapse light mode: snapshot (per-frame) or session (whole capture) |
TIMELAPSE_CAMERA_SOURCE |
follow |
Timelapse camera source: follow, printer, or external |
| Home Assistant MQTT Discovery | ||
HA_MQTT_ENABLED |
false |
Enable Home Assistant MQTT Discovery integration |
HA_MQTT_HOST |
localhost |
Home Assistant MQTT broker host |
HA_MQTT_PORT |
1883 |
Home Assistant MQTT broker port |
HA_MQTT_USER |
(unset) | MQTT broker username |
HA_MQTT_PASSWORD |
(unset) | MQTT broker password |
HA_MQTT_DISCOVERY_PREFIX |
homeassistant |
Home Assistant discovery topic prefix |
HA_MQTT_TOPIC_PREFIX |
ankerctl |
State/command topic prefix |
Tip See
.env.examplefor a ready-to-use template with comments.
ankerctl supports push notifications via Apprise, which supports many notification services including Discord, Telegram, Slack, Pushover, and email.
- Configure notifications in the Setup -> Notifications page
- Or configure them with environment variables
ankerctl requires an Apprise API server rather than only the CLI package. You can:
- run the Apprise API Docker container
- use a hosted Apprise API instance
# Connection settings
APPRISE_ENABLED=true
APPRISE_SERVER_URL=http://apprise:8000 # Your Apprise API server URL
APPRISE_KEY=ankerctl # Apprise notification key/ID
APPRISE_TAG=critical # Optional: Apprise tag filter
# Event toggles (set to true/false)
APPRISE_EVENT_PRINT_STARTED=true # Notify when print starts
APPRISE_EVENT_PRINT_FINISHED=true # Notify when print completes
APPRISE_EVENT_PRINT_FAILED=true # Notify when print fails
APPRISE_EVENT_GCODE_UPLOADED=true # Notify when G-code uploaded
APPRISE_EVENT_PRINT_PROGRESS=true # Notify on print progress updates
# Progress notification settings
APPRISE_PROGRESS_INTERVAL=25 # Progress interval (e.g., every 25%)
APPRISE_PROGRESS_INCLUDE_IMAGE=false # Attach camera snapshot to progress notifications
APPRISE_SNAPSHOT_QUALITY=hd # Snapshot quality: 'sd', 'hd', or 'fhd' (1920x1080)
APPRISE_SNAPSHOT_FALLBACK=true # Use G-code preview if live snapshot fails
APPRISE_PROGRESS_MAX=0 # Override progress scale (0=auto)- Open Setup -> Notifications
- Enter your Apprise server URL and key
- Enable the events you want
- Click Send test
- Confirm the notification arrives
When image attachments are enabled for progress or finish notifications, ankerctl will:
- try to capture a live camera snapshot
- fall back to the G-code preview if live capture fails and fallback is enabled
- send a text-only notification if neither image source works
Note Live snapshots require a working PPPP connection and video stream.
ankerctl automatically records every print to a local SQLite database and shows it in the History tab.
- filename
- start time
- finish time
- duration
- result (
finished,failed,cancelled)
PRINT_HISTORY_RETENTION_DAYS- entries older than this are pruned automaticallyPRINT_HISTORY_MAX_ENTRIES- oldest entries are pruned when the maximum is reached
GET /api/history- list entries (supports?limit=and?offset=)DELETE /api/history- clear all history (requires API key if configured)
No setup is required. History is recorded automatically.
ankerctl can capture a timelapse video automatically for every print.
ffmpeg must be installed and available in PATH.
- captures a snapshot every
TIMELAPSE_INTERVAL_SECseconds - assembles frames into an MP4 at print end
- saves a partial video if the print fails
- supports a resume window so a resumed print can continue appending to the same timelapse
- prunes old videos when
TIMELAPSE_MAX_VIDEOSis reached
Configure TIMELAPSE_LIGHT globally or through the Setup page.
snapshot- turn the light on for each frame, then back offsession- keep the light on for the whole capture session- unset - do not change the light automatically
Configure TIMELAPSE_CAMERA_SOURCE globally or choose the source in Setup -> Timelapse per printer.
follow- use the Home page selected camera sourceprinter- always use the built-in printer cameraexternal- always use the configured external camera
This lets the Home page viewer switch between camera feeds without changing an active timelapse capture source.
Videos can be listed, downloaded, and deleted from the Timelapse tab.
GET /api/timelapses- list available videos with metadataGET /api/timelapse/<filename>- download a videoDELETE /api/timelapse/<filename>- delete a videoGET /api/settings/timelapsePOST /api/settings/timelapse
ankerctl supports:
- the built-in printer camera
- manual snapshot capture
- timelapse frame capture
- optional external camera feeds configured through the web UI
Use Home to choose the viewing and manual-snapshot source. Use Setup -> Timelapse to choose a separate timelapse source when you do not want viewing changes to affect capture.
ankerctl supports Home Assistant MQTT Discovery, publishing printer state directly to your Home Assistant instance.
A running MQTT broker such as Mosquitto that both ankerctl and Home Assistant can reach.
- print progress, state, filename, speed, and current layer
- nozzle and bed temperatures
- elapsed and remaining time
- MQTT connected and PPPP connected binary sensors
- printer light switch, including bidirectional control
- camera stream entity
- Configure the
HA_MQTT_*variables shown above, or - Use Setup -> Home Assistant in the web UI
GET /api/settings/mqttPOST /api/settings/mqtt
Enable the Debug tab by setting:
ANKERCTL_DEV_MODE=trueA Debug tab then appears in the web UI.
Warning Do not enable this in production. The Debug tab exposes internal state and allows simulated events.
- State Inspector - live JSON dump of current print state
- Controls - toggle verbose MQTT payload logging
- Simulation - fire synthetic events without a real printer
- Services - live service health panel with restart actions
- Log Viewer - browse log files from
ANKERCTL_LOG_DIRwith filtering
When an API key is configured, all /api/debug/* endpoints require authentication.
The Setup -> Tools area includes a Bed Level Map tool that reads the bilinear compensation grid directly from the printer.
- Run a
G29auto-level cycle - Open Setup -> Tools
- Click Read from printer
- Review the heatmap and compare saved before/after snapshots
While G29 is running, the UI can show how many of the 49 probe points have completed.
GET /api/printer/bed-leveling- returns{grid, min, max, rows, cols}
Do not call this during an active print.
# Run the web server
./ankerctl.py webserver run
# Set an API key for web authentication
./ankerctl.py config set-password
# Attempt to detect printers on the local network
./ankerctl.py pppp lan-search
# Monitor MQTT events
./ankerctl.py mqtt monitor
# Start an interactive G-code prompt
./ankerctl.py mqtt gcode
# Rename the printer
./ankerctl.py mqtt rename-printer BoatyMcBoatFace
# Print a G-code file
./ankerctl.py pppp print-file boaty.gcode
# Capture 4 MB of camera video
./ankerctl.py pppp capture-video -m 4mb output.h264
# Select which configured printer to use
./ankerctl.py -p <index>If you run ankerctl on a host with a stateful firewall such as ufw (Ubuntu/Debian default), the printer's UDP replies for LAN discovery and PPPP sessions can be silently dropped unless you allow the right ports. Since the fix for issue #77, ankerctl binds its LAN sockets to predictable local ports, so you only need one or two static rules.
sudo ufw allow in proto udp to any port 32108This single rule covers both:
- the LAN discovery broadcast socket (
open_broadcast, sends to255.255.255.255:32108) - the LAN session socket (
open_lan, sends to<printer-ip>:32108)
Both sockets bind locally to UDP 32108 (PPPP_LAN_PORT), so the printer's PunchPkt and follow-up replies hit the same port and the rule matches.
The cloud relay socket (open_wan) is intentionally left ephemeral so it does not collide with the LAN socket. Cloud responses transit NAT, which tracks the connection regardless of local port, so no extra rule is normally required. Only add the rule below if you have confirmed your environment needs it:
sudo ufw allow in proto udp to any port 32100 # only if needed for WAN modeIf you also want to reach the web UI or the slicer upload endpoint from another machine, allow the TCP port the web server is bound to (default 4470):
sudo ufw allow in proto tcp to any port 4470Tip If LAN discovery still hangs at "Connecting" after enabling these rules, double-check that the printer is on the same broadcast domain (no router/VLAN between the host and the printer) and that no second
ankerctlinstance is already holding port32108— the new bind will raiseRuntimeError: PPPP local port 32108 already in use.
For the full design rationale and the underlying socket changes in libflagship/ppppapi.py, see documentation/issue77_code_fix.md.
- GitHub Repository
- GitHub Issues
- eufyMake Support
- Installation from Git
- Installation from Docker
- Project Wiki
This project is not endorsed, affiliated with, or supported by AnkerMake. All information here has been gathered from reverse engineering using publicly available knowledge and resources.
The goal of this project is to make the AnkerMake M5 usable and accessible using only Free and Open Source Software (FOSS).
This project is licensed under the GNU GPLv3, copyright © 2023 Christian Iversen.
Some icons are from IconFinder and are licensed under Creative Commons.

