diff --git a/README.md b/README.md
index 53f694c..d465b1f 100644
--- a/README.md
+++ b/README.md
@@ -40,11 +40,14 @@ How to setup:
- On the website pick the slot you put your filament in
- Done
+Notes:
+ - If you change the BASE_URL of this app, you will need to reconfigure all NFC TAGS
+
TBD:
- Filament remaining in AMS (I have only AMS lite, if you have AMS we can test together)
- Filament spending based on printing
- Evidently needed GUI improvements
- Code cleanup
- Deployment as Docker and Helm chart
- - Easy configuration via env properties
- Video showcase
+ - TODOs
diff --git a/app.py b/app.py
index 155c19e..8db9657 100644
--- a/app.py
+++ b/app.py
@@ -1,16 +1,17 @@
import json
import uuid
-import requests
from flask import Flask, request, render_template_string
-from config import BASE_URL, PRINTER_ID, SPOOLMAN_API_URL
+from config import BASE_URL
from filament import generate_filament_brand_code, generate_filament_temperatures
from messages import AMS_FILAMENT_SETTING
-from mqtt_bambulab import fetchSpools, getLastAMSConfig, publish, getMqttClient
+from mqtt_bambulab import fetchSpools, getLastAMSConfig, publish, getMqttClient, setActiveTray
+from spoolman_client import patchExtraTags, getSpoolById
app = Flask(__name__)
+
@app.route("/spool_info")
def spool_info():
tag_id = request.args.get("tag_id")
@@ -68,6 +69,7 @@ def spool_info():
return render_template_string(html)
+
@app.route("/tray_load")
def tray_load():
tag_id = request.args.get("tag_id")
@@ -80,25 +82,15 @@ def tray_load():
try:
# Update Spoolman with the selected tray
- response = requests.patch(f"{SPOOLMAN_API_URL}/spool/{spool_id}", json={
- "extra": {
- "tag": json.dumps(tag_id),
- "active_tray": json.dumps(f"{PRINTER_ID}_{ams_id}_{tray_id}"),
- }
- })
- print(response.status_code)
- print(response.text)
+ spool_data = getSpoolById(spool_id)
- response = requests.get(f"{SPOOLMAN_API_URL}/spool/{spool_id}")
- print(response.status_code)
- print(response.text)
+ setActiveTray(spool_id, spool_data["extra"], ams_id, tray_id)
- spool_data = json.loads(response.text)
ams_message = AMS_FILAMENT_SETTING
ams_message["print"]["sequence_id"] = 0
ams_message["print"]["ams_id"] = int(ams_id)
ams_message["print"]["tray_id"] = int(tray_id)
- ams_message["print"]["tray_color"] = spool_data["filament"]["color_hex"].upper()+"FF"
+ ams_message["print"]["tray_color"] = spool_data["filament"]["color_hex"].upper() + "FF"
if "nozzle_temperature" in spool_data["filament"]["extra"]:
nozzle_temperature_range = spool_data["filament"]["extra"]["nozzle_temperature"].strip("[]").split(",")
@@ -112,11 +104,12 @@ def tray_load():
ams_message["print"]["tray_type"] = spool_data["filament"]["material"]
filament_brand_code = generate_filament_brand_code(spool_data["filament"]["material"],
- spool_data["filament"]["vendor"]["name"],
- spool_data["filament"]["extra"].get("type", ""))
+ spool_data["filament"]["vendor"]["name"],
+ spool_data["filament"]["extra"].get("type", ""))
ams_message["print"]["tray_info_idx"] = filament_brand_code["brand_code"]
- #ams_message["print"]["tray_sub_brands"] = filament_brand_code["sub_brand_code"]
+ # TODO: test sub_brand_code
+ # ams_message["print"]["tray_sub_brands"] = filament_brand_code["sub_brand_code"]
ams_message["print"]["tray_sub_brands"] = ""
print(ams_message)
@@ -129,10 +122,10 @@ def tray_load():
except Exception as e:
return f"
Error
{str(e)}
"
+
@app.route("/")
def home():
try:
- # Update Spoolman with the selected tray
spools = fetchSpools()
last_ams_config = getLastAMSConfig()
@@ -176,6 +169,7 @@ def home():
except Exception as e:
return f"Error
{str(e)}
"
+
@app.route("/assign_tag")
def assign_tag():
spool_id = request.args.get("spool_id")
@@ -185,15 +179,10 @@ def assign_tag():
myuuid = str(uuid.uuid4())
- resp = requests.patch(f"{SPOOLMAN_API_URL}/spool/{spool_id}", json={
- "extra": {
- "tag": json.dumps(myuuid),
- }
+ patchExtraTags(spool_id, {}, {
+ "tag": json.dumps(myuuid),
})
- print(resp.status_code)
- print(resp.raw)
-
return f"""
@@ -217,6 +206,7 @@ def assign_tag():
"""
+
@app.route('/', methods=['GET'])
def health():
return "OK", 200
diff --git a/mqtt_bambulab.py b/mqtt_bambulab.py
index 3975b1f..f52d35b 100644
--- a/mqtt_bambulab.py
+++ b/mqtt_bambulab.py
@@ -4,15 +4,16 @@ import traceback
from threading import Thread
import paho.mqtt.client as mqtt
-import requests
-from config import PRINTER_ID, PRINTER_CODE, PRINTER_IP, SPOOLMAN_API_URL
+from config import PRINTER_ID, PRINTER_CODE, PRINTER_IP
from messages import GET_VERSION, PUSH_ALL
+from spoolman_client import fetchSpoolList, patchExtraTags
def num2letter(num):
return chr(ord("A") + int(num))
+
def publish(client, msg):
result = client.publish(f"device/{PRINTER_ID}/request", json.dumps(msg))
status = result[0]
@@ -23,12 +24,14 @@ def publish(client, msg):
print(f"Failed to send message to topic device/{PRINTER_ID}/request")
return False
+
# Inspired by https://github.com/Donkie/Spoolman/issues/217#issuecomment-2303022970
def on_message(client, userdata, msg):
global LAST_AMS_CONFIG
# TODO: Consume spool
try:
data = json.loads(msg.payload.decode())
+ print(data)
if "print" in data and "vt_tray" in data["print"]:
print(data)
LAST_AMS_CONFIG["vt_tray"] = data["print"]["vt_tray"]
@@ -42,7 +45,8 @@ def on_message(client, userdata, msg):
print(f"AMS [{num2letter(ams['id'])}] (hum: {ams['humidity']}, temp: {ams['temp']}ÂșC)")
for tray in ams["tray"]:
if "tray_sub_brands" in tray:
- print(f" - [{num2letter(ams['id'])}{tray['id']}] {tray['tray_sub_brands']} {tray['tray_color']} ({str(tray['remain']).zfill(3)}%) [[ {tray['tag_uid']} ]]")
+ print(
+ f" - [{num2letter(ams['id'])}{tray['id']}] {tray['tray_sub_brands']} {tray['tray_color']} ({str(tray['remain']).zfill(3)}%) [[ {tray['tag_uid']} ]]")
found = False
for spool in SPOOLS:
@@ -54,40 +58,45 @@ def on_message(client, userdata, msg):
found = True
- resp = requests.patch(f"{SPOOLMAN_API_URL}/spool/{spool['id']}", json={
- "extra": {
- "tag": spool["extra"]["tag"],
- "active_tray": json.dumps(f"{PRINTER_ID}_{ams['id']}_{tray['id']}"),
- }
- })
+ setActiveTray(spool['id'], spool["extra"], ams['id'], tray["id"])
- print(resp.text)
- print(resp.status_code)
-
- #TODO: remove active_tray from inactive spools
- #Doesn't work for AMS Lite
- #requests.patch(f"http://{SPOOLMAN_IP}:7912/api/v1/spool/{spool['id']}", json={
+ # TODO: filament remaining - Doesn't work for AMS Lite
+ # requests.patch(f"http://{SPOOLMAN_IP}:7912/api/v1/spool/{spool['id']}", json={
# "remaining_weight": tray["remain"] / 100 * tray["tray_weight"]
- #})
+ # })
- if not found:
- print(" - Not found. Update spool tag!")
+ if not found:
+ print(" - Not found. Update spool tag!")
except Exception as e:
traceback.print_exc()
+
def on_connect(client, userdata, flags, rc):
- print("Connected with result code "+str(rc))
+ print("Connected with result code " + str(rc))
client.subscribe(f"device/{PRINTER_ID}/report")
publish(client, GET_VERSION)
publish(client, PUSH_ALL)
+
+def setActiveTray(spool_id, spool_extra, ams_id, tray_id):
+ patchExtraTags(spool_id, spool_extra, {
+ "active_tray": json.dumps(f"{PRINTER_ID}_{ams_id}_{tray_id}"),
+ })
+
+ # Remove active tray from inactive spools
+ for old_spool in SPOOLS:
+ if spool_id != old_spool["id"] and old_spool["extra"]["active_tray"] == json.dumps(
+ f"{PRINTER_ID}_{ams_id}_{tray_id}"):
+ patchExtraTags(old_spool["id"], old_spool["extra"], {"active_tray": json.dumps("")})
+
+
# Fetch spools from spoolman
def fetchSpools():
global SPOOLS
- response = requests.get(f"{SPOOLMAN_API_URL}/spool")
- SPOOLS = response.json()
+ SPOOLS = fetchSpoolList()
return SPOOLS
+
def async_subscribe():
global MQTT_CLIENT
MQTT_CLIENT = mqtt.Client()
@@ -102,18 +111,22 @@ def async_subscribe():
MQTT_CLIENT.connect(PRINTER_IP, 8883)
MQTT_CLIENT.loop_forever()
+
# Start the asynchronous processing in a separate thread
thread = Thread(target=async_subscribe)
thread.start()
+
def getLastAMSConfig():
global LAST_AMS_CONFIG
return LAST_AMS_CONFIG
+
def getMqttClient():
global MQTT_CLIENT
return MQTT_CLIENT
-MQTT_CLIENT = {} # Global variable storing MQTT Client
+
+MQTT_CLIENT = {} # Global variable storing MQTT Client
LAST_AMS_CONFIG = {} # Global variable storing last AMS configuration
-SPOOLS = fetchSpools() # Global variable storing latest spool from spoolman
+SPOOLS = fetchSpools() # Global variable storing latest spool from spoolman
diff --git a/spoolman_client.py b/spoolman_client.py
new file mode 100644
index 0000000..930a39b
--- /dev/null
+++ b/spoolman_client.py
@@ -0,0 +1,27 @@
+import requests
+from config import SPOOLMAN_API_URL
+
+
+def patchExtraTags(spool_id, old_extras, new_extras):
+ for key, value in new_extras.items():
+ old_extras[key] = value
+
+ resp = requests.patch(f"{SPOOLMAN_API_URL}/spool/{spool_id}", json={
+ "extra": old_extras
+ })
+ print(resp.text)
+ print(resp.status_code)
+
+
+def getSpoolById(spool_id):
+ response = requests.get(f"{SPOOLMAN_API_URL}/spool/{spool_id}")
+ print(response.status_code)
+ print(response.text)
+ return response.json()
+
+
+def fetchSpoolList():
+ response = requests.get(f"{SPOOLMAN_API_URL}/spool")
+ print(response.status_code)
+ print(response.text)
+ return response.json()