mirror of
https://github.com/hanzoskill/bambu-local.git
synced 2026-10-30 21:05:52 +00:00
152 lines
5.1 KiB
Python
152 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Bambu Lab Local Control - Contrôle local via MQTT
|
|
"""
|
|
import ssl
|
|
import json
|
|
import sys
|
|
import time
|
|
import argparse
|
|
import os
|
|
import paho.mqtt.client as mqtt
|
|
|
|
# Charge la config
|
|
CONFIG_PATH = os.path.join(os.path.dirname(__file__), "config.json")
|
|
if os.path.exists(CONFIG_PATH):
|
|
with open(CONFIG_PATH) as f:
|
|
config = json.load(f)
|
|
PRINTER_IP = config.get("printer_ip", "")
|
|
ACCESS_CODE = config.get("access_code", "")
|
|
SERIAL = config.get("serial", "")
|
|
PRINTER_NAME = config.get("printer_name", "Printer")
|
|
else:
|
|
print("❌ config.json manquant. Crée-le avec tes infos imprimante.")
|
|
sys.exit(1)
|
|
|
|
status_data = {}
|
|
seq_id = 0
|
|
|
|
def get_client():
|
|
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
|
|
client.username_pw_set("bblp", ACCESS_CODE)
|
|
client.tls_set(cert_reqs=ssl.CERT_NONE)
|
|
client.tls_insecure_set(True)
|
|
return client
|
|
|
|
def on_connect(client, userdata, flags, rc, properties=None):
|
|
client.subscribe(f"device/{SERIAL}/report")
|
|
|
|
def on_message(client, userdata, msg):
|
|
global status_data
|
|
try:
|
|
data = json.loads(msg.payload)
|
|
if "print" in data:
|
|
status_data.update(data["print"])
|
|
except:
|
|
pass
|
|
|
|
def send_command(cmd):
|
|
global seq_id
|
|
client = get_client()
|
|
client.connect(PRINTER_IP, 8883, 60)
|
|
client.loop_start()
|
|
time.sleep(1)
|
|
seq_id += 1
|
|
cmd["sequence_id"] = str(seq_id)
|
|
topic = f"device/{SERIAL}/request"
|
|
client.publish(topic, json.dumps(cmd))
|
|
time.sleep(1)
|
|
client.loop_stop()
|
|
client.disconnect()
|
|
|
|
def get_status():
|
|
client = get_client()
|
|
client.on_connect = on_connect
|
|
client.on_message = on_message
|
|
client.connect(PRINTER_IP, 8883, 60)
|
|
client.loop_start()
|
|
time.sleep(3)
|
|
client.loop_stop()
|
|
client.disconnect()
|
|
|
|
print(f"🖨️ {PRINTER_NAME} (Bambu Lab)")
|
|
print(f" IP: {PRINTER_IP}")
|
|
print(f" Serial: {SERIAL}")
|
|
print(f" ─────────────────────────")
|
|
print(f" 🌡️ Lit: {status_data.get('bed_temper', 'N/A')}°C / {status_data.get('bed_target_temper', 0)}°C")
|
|
print(f" 🌡️ Buse: {status_data.get('nozzle_temper', 'N/A')}°C / {status_data.get('nozzle_target_temper', 0)}°C")
|
|
print(f" 📶 WiFi: {status_data.get('wifi_signal', 'N/A')}")
|
|
print(f" ⚙️ État: {status_data.get('gcode_state', 'IDLE')}")
|
|
|
|
if status_data.get('gcode_state') == 'RUNNING':
|
|
print(f" 📊 Progression: {status_data.get('mc_percent', 0)}%")
|
|
remaining = status_data.get('mc_remaining_time', 0)
|
|
if remaining:
|
|
print(f" ⏱️ Restant: {remaining // 60}h{remaining % 60}m")
|
|
print(f" 🎯 Couche: {status_data.get('layer_num', 0)}/{status_data.get('total_layer_num', 0)}")
|
|
|
|
def light_control(state):
|
|
cmd = {"system": {"command": "ledctrl", "led_node": "chamber_light", "led_mode": "on" if state else "off"}}
|
|
send_command(cmd)
|
|
print(f"💡 Lumière {'allumée' if state else 'éteinte'}")
|
|
|
|
def print_control(action):
|
|
cmd = {"print": {"command": action}}
|
|
send_command(cmd)
|
|
actions_fr = {"pause": "en pause", "resume": "reprise", "stop": "arrêtée"}
|
|
print(f"🖨️ Impression {actions_fr.get(action, action)}")
|
|
|
|
def set_speed(level):
|
|
cmd = {"print": {"command": "print_speed", "param": str(level)}}
|
|
send_command(cmd)
|
|
speeds = {1: "Silencieux", 2: "Standard", 3: "Sport", 4: "Ludicrous"}
|
|
print(f"⚡ Vitesse: {speeds.get(level, level)}")
|
|
|
|
def set_temps(bed=None, nozzle=None):
|
|
if bed is not None:
|
|
send_command({"print": {"command": "gcode_line", "param": f"M140 S{bed}"}})
|
|
print(f"🌡️ Lit: {bed}°C")
|
|
if nozzle is not None:
|
|
send_command({"print": {"command": "gcode_line", "param": f"M104 S{nozzle}"}})
|
|
print(f"🌡️ Buse: {nozzle}°C")
|
|
|
|
def send_gcode(gcode):
|
|
cmd = {"print": {"command": "gcode_line", "param": gcode}}
|
|
send_command(cmd)
|
|
print(f"📤 G-code: {gcode}")
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=f"Contrôle {PRINTER_NAME}")
|
|
subparsers = parser.add_subparsers(dest="command")
|
|
|
|
subparsers.add_parser("status")
|
|
light_p = subparsers.add_parser("light")
|
|
light_p.add_argument("state", choices=["on", "off"])
|
|
print_p = subparsers.add_parser("print")
|
|
print_p.add_argument("action", choices=["pause", "resume", "stop"])
|
|
speed_p = subparsers.add_parser("speed")
|
|
speed_p.add_argument("level", type=int, choices=[1, 2, 3, 4])
|
|
temp_p = subparsers.add_parser("temp")
|
|
temp_p.add_argument("--bed", type=int)
|
|
temp_p.add_argument("--nozzle", type=int)
|
|
gcode_p = subparsers.add_parser("gcode")
|
|
gcode_p.add_argument("code")
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.command == "status" or args.command is None:
|
|
get_status()
|
|
elif args.command == "light":
|
|
light_control(args.state == "on")
|
|
elif args.command == "print":
|
|
print_control(args.action)
|
|
elif args.command == "speed":
|
|
set_speed(args.level)
|
|
elif args.command == "temp":
|
|
set_temps(args.bed, args.nozzle)
|
|
elif args.command == "gcode":
|
|
send_gcode(args.code)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|