MrDraw/Cura/webui/__init__.py
Gina Häußge 375fffdd3f Upload location is now platform dependent
win32 defaults to %APPDATA%/Cura/uploads
macos defaults to ~/Library/Application Support/Cura/uploads (I hope, can't test it...)
linux defaults to ~/.cura/uploads

Server now also checks if file to be uploaded or deleted ends on .gcode and makes filename secure before doing anything on the filesystem

Also added favicon ;) and some bla to the README.md
2012-12-27 00:04:12 +01:00

223 lines
6.2 KiB
Python

#!/usr/bin/env python
# coding=utf-8
__author__ = 'Gina Häußge <osd@foosel.net>'
from flask import Flask, request, render_template, jsonify, make_response
from werkzeug import secure_filename
from printer import Printer
import sys
import os
import fnmatch
APPNAME="Cura"
BASEURL="/ajax/"
SUCCESS={}
# taken from http://stackoverflow.com/questions/1084697/how-do-i-store-desktop-application-data-in-a-cross-platform-way-for-python
if sys.platform == 'darwin':
from AppKit import NSSearchPathForDirectoriesInDomains
# http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/c/func/NSSearchPathForDirectoriesInDomains
# NSApplicationSupportDirectory = 14
# NSUserDomainMask = 1
# True for expanding the tilde into a fully qualified path
appdata = os.path.join(NSSearchPathForDirectoriesInDomains(14, 1, True)[0], APPNAME)
elif sys.platform == 'win32':
appdata = os.path.join(os.environ['APPDATA'], APPNAME)
else:
appdata = os.path.expanduser(os.path.join("~", "." + APPNAME.lower()))
UPLOAD_FOLDER = appdata + os.sep + "uploads"
if not os.path.isdir(UPLOAD_FOLDER):
os.makedirs(UPLOAD_FOLDER)
ALLOWED_EXTENSIONS = set(["gcode"])
app = Flask("Cura.webui")
printer = Printer()
@app.route('/')
def index():
return render_template('index.html')
#~~ Printer state
@app.route(BASEURL + 'state', methods=['GET'])
def printerState():
temp = printer.currentTemp
bedTemp = printer.currentBedTemp
targetTemp = printer.currentTargetTemp
bedTargetTemp = printer.currentBedTargetTemp
jobData = printer.jobData()
result = {
'state': printer.getStateString(),
'temp': temp,
'bedTemp': bedTemp,
'targetTemp': targetTemp,
'targetBedTemp': bedTargetTemp,
'operational': printer.isOperational(),
'closedOrError': printer.isClosedOrError(),
'error': printer.isError(),
'printing': printer.isPrinting(),
'paused': printer.isPaused(),
'ready': printer.isReady()
}
if (jobData != None):
result['job'] = jobData
if (request.values.has_key('temperatures')):
result['temperatures'] = printer.temps
if (request.values.has_key('log')):
result['log'] = printer.log
if (request.values.has_key('messages')):
result['messages'] = printer.messages
return jsonify(result)
@app.route(BASEURL + 'state/messages', methods=['GET'])
def printerMessages():
return jsonify(messages=printer.messages)
@app.route(BASEURL + 'state/log', methods=['GET'])
def printerLogs():
return jsonify(log=printer.log)
@app.route(BASEURL + 'state/temperatures', methods=['GET'])
def printerTemperatures():
return jsonify(temperatures = printer.temps)
#~~ Printer control
@app.route(BASEURL + 'control/connect', methods=['POST'])
def connect():
printer.connect()
return jsonify(state='Connecting')
@app.route(BASEURL + 'control/disconnect', methods=['POST'])
def disconnect():
printer.disconnect()
return jsonify(state='Offline')
@app.route(BASEURL + 'control/command', methods=['POST'])
def printerCommand():
command = request.form['command']
printer.command(command)
return jsonify(SUCCESS)
@app.route(BASEURL + 'control/print', methods=['POST'])
def printGcode():
printer.startPrint()
return jsonify(SUCCESS)
@app.route(BASEURL + 'control/pause', methods=['POST'])
def pausePrint():
printer.togglePausePrint()
return jsonify(SUCCESS)
@app.route(BASEURL + 'control/cancel', methods=['POST'])
def cancelPrint():
printer.cancelPrint()
return jsonify(SUCCESS)
@app.route(BASEURL + 'control/temperature', methods=['POST'])
def setTargetTemperature():
if not printer.isOperational():
return jsonify(SUCCESS)
if request.values.has_key("temp"):
# set target temperature
temp = request.values["temp"];
printer.command("M104 S" + temp)
if request.values.has_key("bedTemp"):
# set target bed temperature
bedTemp = request.values["bedTemp"]
printer.command("M140 S" + bedTemp)
return jsonify(SUCCESS)
@app.route(BASEURL + "control/jog", methods=["POST"])
def jog():
if not printer.isOperational() or printer.isPrinting():
# do not jog when a print job is running or we don't have a connection
return jsonify(SUCCESS)
if request.values.has_key("x"):
# jog x
x = request.values["x"]
printer.commands(["G91", "G1 X" + x + " F6000", "G90"])
if request.values.has_key("y"):
# jog y
y = request.values["y"]
printer.commands(["G91", "G1 Y" + y + " F6000", "G90"])
if request.values.has_key("z"):
# jog z
z = request.values["z"]
printer.commands(["G91", "G1 Z" + z + " F200", "G90"])
if request.values.has_key("homeXY"):
# home x/y
printer.command("G28 X0 Y0")
if request.values.has_key("homeZ"):
# home z
printer.command("G28 Z0")
return jsonify(SUCCESS)
#~~ GCODE file handling
@app.route(BASEURL + 'gcodefiles', methods=['GET'])
def readGcodeFiles():
files = []
for osFile in os.listdir(UPLOAD_FOLDER):
if not fnmatch.fnmatch(osFile, "*.gcode"):
continue
files.append({
"name": osFile,
"size": sizeof_fmt(os.stat(UPLOAD_FOLDER + os.sep + osFile).st_size)
})
return jsonify(files=files)
@app.route(BASEURL + 'gcodefiles/upload', methods=['POST'])
def uploadGcodeFile():
file = request.files['gcode_file']
if file and allowed_file(file.filename):
secure = secure_filename(file.filename)
filename = os.path.join(UPLOAD_FOLDER, secure)
file.save(filename)
return readGcodeFiles()
@app.route(BASEURL + 'gcodefiles/load', methods=['POST'])
def loadGcodeFile():
filename = request.values["filename"]
printer.loadGcode(UPLOAD_FOLDER + os.sep + filename)
return jsonify(SUCCESS)
@app.route(BASEURL + 'gcodefiles/delete', methods=['POST'])
def deleteGcodeFile():
if request.values.has_key("filename"):
filename = request.values["filename"]
if allowed_file(filename):
secure = UPLOAD_FOLDER + os.sep + secure_filename(filename)
if os.path.exists(secure):
os.remove(secure)
return readGcodeFiles()
def sizeof_fmt(num):
"""
Taken from http://stackoverflow.com/questions/1094841/reusable-library-to-get-human-readable-version-of-file-size
"""
for x in ['bytes','KB','MB','GB']:
if num < 1024.0:
return "%3.1f%s" % (num, x)
num /= 1024.0
return "%3.1f%s" % (num, 'TB')
def allowed_file(filename):
return "." in filename and filename.rsplit(".", 1)[1] in ALLOWED_EXTENSIONS
def run():
app.run(host="0.0.0.0", port=5000)