mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 11:12:35 +02:00
- New APIBrowser component with full OpenAPI schema integration
- Fetches and parses /openapi.json automatically
- Groups endpoints by API tags (printers, archives, settings, etc.)
- Expandable endpoint sections with color-coded method badges
- Path parameter, query parameter, and JSON body editors
- Auto-populates request body with schema examples
- Live API request execution with response display
- Response shows status code, timing, and formatted JSON
- Copy response button with clipboard fallback
- Search to filter endpoints across all categories
- Expand All / Collapse All buttons
- Link to Swagger UI (/docs)
- Two-column layout for API Keys tab
- Left: API key management + webhook documentation
- Right: API Browser with dedicated test key input
- Parameter validation
- Shows warning for missing required parameters
- Validates before sending requests to avoid 422 errors
- UX improvements
- "Use in API Browser" button on newly created keys
- Responsive layout (stacked on mobile, side-by-side on xl+)
122 lines
3.9 KiB
Python
122 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""MQTT Sniffer for Bambu Lab printers.
|
|
|
|
Connects to a printer and logs all MQTT messages to capture the exact
|
|
command format used by OrcaSlicer or Bambu Studio.
|
|
|
|
Usage:
|
|
python mqtt_sniffer.py <printer_ip> <serial_number> <access_code>
|
|
|
|
Example:
|
|
python mqtt_sniffer.py 192.168.1.100 0948BB540200427 12345678
|
|
"""
|
|
|
|
import json
|
|
import ssl
|
|
import sys
|
|
from datetime import datetime
|
|
|
|
import paho.mqtt.client as mqtt
|
|
|
|
|
|
def on_connect(client, userdata, flags, rc):
|
|
"""Called when connected to the MQTT broker."""
|
|
if rc == 0:
|
|
print(f"[{datetime.now().strftime('%H:%M:%S')}] Connected to printer!")
|
|
serial = userdata["serial"]
|
|
# Subscribe to all topics for this printer
|
|
topic_report = f"device/{serial}/report"
|
|
client.subscribe(topic_report)
|
|
print(f"[{datetime.now().strftime('%H:%M:%S')}] Subscribed to: {topic_report}")
|
|
print("-" * 80)
|
|
print("Listening for MQTT messages... Press Ctrl+C to stop.")
|
|
print("Now use OrcaSlicer to add a K-profile and the command will be logged here.")
|
|
print("-" * 80)
|
|
else:
|
|
print(f"[{datetime.now().strftime('%H:%M:%S')}] Connection failed with code: {rc}")
|
|
|
|
|
|
def on_message(client, userdata, msg):
|
|
"""Called when a message is received."""
|
|
try:
|
|
payload = json.loads(msg.payload.decode("utf-8"))
|
|
|
|
# Check if this is an extrusion_cali related message
|
|
is_cali_msg = False
|
|
command = None
|
|
|
|
if "print" in payload:
|
|
command = payload["print"].get("command", "")
|
|
if "extrusion_cali" in command:
|
|
is_cali_msg = True
|
|
|
|
# Always log calibration messages with full detail
|
|
if is_cali_msg:
|
|
print(f"\n{'='*80}")
|
|
print(f"[{datetime.now().strftime('%H:%M:%S.%f')[:-3]}] *** CALIBRATION COMMAND: {command} ***")
|
|
print(f"Topic: {msg.topic}")
|
|
print("Full payload:")
|
|
print(json.dumps(payload, indent=2))
|
|
print(f"{'='*80}\n")
|
|
else:
|
|
# For other messages, just show a brief summary
|
|
if "print" in payload:
|
|
cmd = payload["print"].get("command", "unknown")
|
|
# Skip noisy status messages
|
|
if cmd not in ["push_status"]:
|
|
print(f"[{datetime.now().strftime('%H:%M:%S')}] Command: {cmd}")
|
|
|
|
except json.JSONDecodeError:
|
|
print(f"[{datetime.now().strftime('%H:%M:%S')}] Non-JSON message on {msg.topic}")
|
|
except Exception as e:
|
|
print(f"[{datetime.now().strftime('%H:%M:%S')}] Error processing message: {e}")
|
|
|
|
|
|
def on_disconnect(client, userdata, rc):
|
|
"""Called when disconnected from the MQTT broker."""
|
|
print(f"[{datetime.now().strftime('%H:%M:%S')}] Disconnected with code: {rc}")
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) != 4:
|
|
print("Usage: python mqtt_sniffer.py <printer_ip> <serial_number> <access_code>")
|
|
print("\nExample:")
|
|
print(" python mqtt_sniffer.py 192.168.1.100 0948BB540200427 12345678")
|
|
sys.exit(1)
|
|
|
|
printer_ip = sys.argv[1]
|
|
serial_number = sys.argv[2]
|
|
access_code = sys.argv[3]
|
|
|
|
print(f"Connecting to printer at {printer_ip}...")
|
|
print(f"Serial: {serial_number}")
|
|
|
|
# Create MQTT client
|
|
client = mqtt.Client(userdata={"serial": serial_number})
|
|
client.username_pw_set("bblp", access_code)
|
|
|
|
# Configure TLS
|
|
ssl_context = ssl.create_default_context()
|
|
ssl_context.check_hostname = False
|
|
ssl_context.verify_mode = ssl.CERT_NONE
|
|
client.tls_set_context(ssl_context)
|
|
|
|
# Set callbacks
|
|
client.on_connect = on_connect
|
|
client.on_message = on_message
|
|
client.on_disconnect = on_disconnect
|
|
|
|
try:
|
|
client.connect(printer_ip, 8883, 60)
|
|
client.loop_forever()
|
|
except KeyboardInterrupt:
|
|
print("\n\nStopping sniffer...")
|
|
client.disconnect()
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|