Code cleanup: Separate spoolman_client
Bugfix: Unchanged extras must be sent to spoolman for them not to disappear Bugfix: Remove active tray from inactive spools Docs: Add note about the Base_URL
This commit is contained in:
parent
a56c78b24a
commit
3a6ecf8e9f
@ -40,11 +40,14 @@ How to setup:
|
|||||||
- On the website pick the slot you put your filament in
|
- On the website pick the slot you put your filament in
|
||||||
- Done
|
- Done
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- If you change the BASE_URL of this app, you will need to reconfigure all NFC TAGS
|
||||||
|
|
||||||
TBD:
|
TBD:
|
||||||
- Filament remaining in AMS (I have only AMS lite, if you have AMS we can test together)
|
- Filament remaining in AMS (I have only AMS lite, if you have AMS we can test together)
|
||||||
- Filament spending based on printing
|
- Filament spending based on printing
|
||||||
- Evidently needed GUI improvements
|
- Evidently needed GUI improvements
|
||||||
- Code cleanup
|
- Code cleanup
|
||||||
- Deployment as Docker and Helm chart
|
- Deployment as Docker and Helm chart
|
||||||
- Easy configuration via env properties
|
|
||||||
- Video showcase
|
- Video showcase
|
||||||
|
- TODOs
|
||||||
|
34
app.py
34
app.py
@ -1,16 +1,17 @@
|
|||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import requests
|
|
||||||
from flask import Flask, request, render_template_string
|
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 filament import generate_filament_brand_code, generate_filament_temperatures
|
||||||
from messages import AMS_FILAMENT_SETTING
|
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 = Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/spool_info")
|
@app.route("/spool_info")
|
||||||
def spool_info():
|
def spool_info():
|
||||||
tag_id = request.args.get("tag_id")
|
tag_id = request.args.get("tag_id")
|
||||||
@ -68,6 +69,7 @@ def spool_info():
|
|||||||
|
|
||||||
return render_template_string(html)
|
return render_template_string(html)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/tray_load")
|
@app.route("/tray_load")
|
||||||
def tray_load():
|
def tray_load():
|
||||||
tag_id = request.args.get("tag_id")
|
tag_id = request.args.get("tag_id")
|
||||||
@ -80,20 +82,10 @@ def tray_load():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Update Spoolman with the selected tray
|
# Update Spoolman with the selected tray
|
||||||
response = requests.patch(f"{SPOOLMAN_API_URL}/spool/{spool_id}", json={
|
spool_data = getSpoolById(spool_id)
|
||||||
"extra": {
|
|
||||||
"tag": json.dumps(tag_id),
|
|
||||||
"active_tray": json.dumps(f"{PRINTER_ID}_{ams_id}_{tray_id}"),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
print(response.status_code)
|
|
||||||
print(response.text)
|
|
||||||
|
|
||||||
response = requests.get(f"{SPOOLMAN_API_URL}/spool/{spool_id}")
|
setActiveTray(spool_id, spool_data["extra"], ams_id, tray_id)
|
||||||
print(response.status_code)
|
|
||||||
print(response.text)
|
|
||||||
|
|
||||||
spool_data = json.loads(response.text)
|
|
||||||
ams_message = AMS_FILAMENT_SETTING
|
ams_message = AMS_FILAMENT_SETTING
|
||||||
ams_message["print"]["sequence_id"] = 0
|
ams_message["print"]["sequence_id"] = 0
|
||||||
ams_message["print"]["ams_id"] = int(ams_id)
|
ams_message["print"]["ams_id"] = int(ams_id)
|
||||||
@ -116,6 +108,7 @@ def tray_load():
|
|||||||
spool_data["filament"]["extra"].get("type", ""))
|
spool_data["filament"]["extra"].get("type", ""))
|
||||||
ams_message["print"]["tray_info_idx"] = filament_brand_code["brand_code"]
|
ams_message["print"]["tray_info_idx"] = filament_brand_code["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"] = filament_brand_code["sub_brand_code"]
|
||||||
ams_message["print"]["tray_sub_brands"] = ""
|
ams_message["print"]["tray_sub_brands"] = ""
|
||||||
|
|
||||||
@ -129,10 +122,10 @@ def tray_load():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return f"<h1>Error</h1><p>{str(e)}</p>"
|
return f"<h1>Error</h1><p>{str(e)}</p>"
|
||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def home():
|
def home():
|
||||||
try:
|
try:
|
||||||
# Update Spoolman with the selected tray
|
|
||||||
spools = fetchSpools()
|
spools = fetchSpools()
|
||||||
|
|
||||||
last_ams_config = getLastAMSConfig()
|
last_ams_config = getLastAMSConfig()
|
||||||
@ -176,6 +169,7 @@ def home():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return f"<h1>Error</h1><p>{str(e)}</p>"
|
return f"<h1>Error</h1><p>{str(e)}</p>"
|
||||||
|
|
||||||
|
|
||||||
@app.route("/assign_tag")
|
@app.route("/assign_tag")
|
||||||
def assign_tag():
|
def assign_tag():
|
||||||
spool_id = request.args.get("spool_id")
|
spool_id = request.args.get("spool_id")
|
||||||
@ -185,15 +179,10 @@ def assign_tag():
|
|||||||
|
|
||||||
myuuid = str(uuid.uuid4())
|
myuuid = str(uuid.uuid4())
|
||||||
|
|
||||||
resp = requests.patch(f"{SPOOLMAN_API_URL}/spool/{spool_id}", json={
|
patchExtraTags(spool_id, {}, {
|
||||||
"extra": {
|
|
||||||
"tag": json.dumps(myuuid),
|
"tag": json.dumps(myuuid),
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
print(resp.status_code)
|
|
||||||
print(resp.raw)
|
|
||||||
|
|
||||||
return f"""
|
return f"""
|
||||||
<html>
|
<html>
|
||||||
<header>
|
<header>
|
||||||
@ -217,6 +206,7 @@ def assign_tag():
|
|||||||
</html>
|
</html>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@app.route('/', methods=['GET'])
|
@app.route('/', methods=['GET'])
|
||||||
def health():
|
def health():
|
||||||
return "OK", 200
|
return "OK", 200
|
||||||
|
@ -4,15 +4,16 @@ import traceback
|
|||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
import paho.mqtt.client as mqtt
|
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 messages import GET_VERSION, PUSH_ALL
|
||||||
|
from spoolman_client import fetchSpoolList, patchExtraTags
|
||||||
|
|
||||||
|
|
||||||
def num2letter(num):
|
def num2letter(num):
|
||||||
return chr(ord("A") + int(num))
|
return chr(ord("A") + int(num))
|
||||||
|
|
||||||
|
|
||||||
def publish(client, msg):
|
def publish(client, msg):
|
||||||
result = client.publish(f"device/{PRINTER_ID}/request", json.dumps(msg))
|
result = client.publish(f"device/{PRINTER_ID}/request", json.dumps(msg))
|
||||||
status = result[0]
|
status = result[0]
|
||||||
@ -23,12 +24,14 @@ def publish(client, msg):
|
|||||||
print(f"Failed to send message to topic device/{PRINTER_ID}/request")
|
print(f"Failed to send message to topic device/{PRINTER_ID}/request")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
# Inspired by https://github.com/Donkie/Spoolman/issues/217#issuecomment-2303022970
|
# Inspired by https://github.com/Donkie/Spoolman/issues/217#issuecomment-2303022970
|
||||||
def on_message(client, userdata, msg):
|
def on_message(client, userdata, msg):
|
||||||
global LAST_AMS_CONFIG
|
global LAST_AMS_CONFIG
|
||||||
# TODO: Consume spool
|
# TODO: Consume spool
|
||||||
try:
|
try:
|
||||||
data = json.loads(msg.payload.decode())
|
data = json.loads(msg.payload.decode())
|
||||||
|
print(data)
|
||||||
if "print" in data and "vt_tray" in data["print"]:
|
if "print" in data and "vt_tray" in data["print"]:
|
||||||
print(data)
|
print(data)
|
||||||
LAST_AMS_CONFIG["vt_tray"] = data["print"]["vt_tray"]
|
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)")
|
print(f"AMS [{num2letter(ams['id'])}] (hum: {ams['humidity']}, temp: {ams['temp']}ºC)")
|
||||||
for tray in ams["tray"]:
|
for tray in ams["tray"]:
|
||||||
if "tray_sub_brands" in 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
|
found = False
|
||||||
for spool in SPOOLS:
|
for spool in SPOOLS:
|
||||||
@ -54,18 +58,9 @@ def on_message(client, userdata, msg):
|
|||||||
|
|
||||||
found = True
|
found = True
|
||||||
|
|
||||||
resp = requests.patch(f"{SPOOLMAN_API_URL}/spool/{spool['id']}", json={
|
setActiveTray(spool['id'], spool["extra"], ams['id'], tray["id"])
|
||||||
"extra": {
|
|
||||||
"tag": spool["extra"]["tag"],
|
|
||||||
"active_tray": json.dumps(f"{PRINTER_ID}_{ams['id']}_{tray['id']}"),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
print(resp.text)
|
# TODO: filament remaining - Doesn't work for AMS Lite
|
||||||
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={
|
# requests.patch(f"http://{SPOOLMAN_IP}:7912/api/v1/spool/{spool['id']}", json={
|
||||||
# "remaining_weight": tray["remain"] / 100 * tray["tray_weight"]
|
# "remaining_weight": tray["remain"] / 100 * tray["tray_weight"]
|
||||||
# })
|
# })
|
||||||
@ -75,19 +70,33 @@ def on_message(client, userdata, msg):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
def on_connect(client, userdata, flags, rc):
|
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")
|
client.subscribe(f"device/{PRINTER_ID}/report")
|
||||||
publish(client, GET_VERSION)
|
publish(client, GET_VERSION)
|
||||||
publish(client, PUSH_ALL)
|
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
|
# Fetch spools from spoolman
|
||||||
def fetchSpools():
|
def fetchSpools():
|
||||||
global SPOOLS
|
global SPOOLS
|
||||||
response = requests.get(f"{SPOOLMAN_API_URL}/spool")
|
SPOOLS = fetchSpoolList()
|
||||||
SPOOLS = response.json()
|
|
||||||
return SPOOLS
|
return SPOOLS
|
||||||
|
|
||||||
|
|
||||||
def async_subscribe():
|
def async_subscribe():
|
||||||
global MQTT_CLIENT
|
global MQTT_CLIENT
|
||||||
MQTT_CLIENT = mqtt.Client()
|
MQTT_CLIENT = mqtt.Client()
|
||||||
@ -102,18 +111,22 @@ def async_subscribe():
|
|||||||
MQTT_CLIENT.connect(PRINTER_IP, 8883)
|
MQTT_CLIENT.connect(PRINTER_IP, 8883)
|
||||||
MQTT_CLIENT.loop_forever()
|
MQTT_CLIENT.loop_forever()
|
||||||
|
|
||||||
|
|
||||||
# Start the asynchronous processing in a separate thread
|
# Start the asynchronous processing in a separate thread
|
||||||
thread = Thread(target=async_subscribe)
|
thread = Thread(target=async_subscribe)
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
|
|
||||||
def getLastAMSConfig():
|
def getLastAMSConfig():
|
||||||
global LAST_AMS_CONFIG
|
global LAST_AMS_CONFIG
|
||||||
return LAST_AMS_CONFIG
|
return LAST_AMS_CONFIG
|
||||||
|
|
||||||
|
|
||||||
def getMqttClient():
|
def getMqttClient():
|
||||||
global MQTT_CLIENT
|
global MQTT_CLIENT
|
||||||
return 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
|
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
|
||||||
|
27
spoolman_client.py
Normal file
27
spoolman_client.py
Normal file
@ -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()
|
Loading…
x
Reference in New Issue
Block a user