-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.py
215 lines (180 loc) · 6.93 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
import json
import logging
import os
from datetime import datetime
from flask import Flask, redirect, render_template, jsonify, request, url_for, send_file
from database import Database
from camera import Camera
from extractor import Extractor
from plot import Plotter
from logger import setup_logger
# Setup Flask app
app = Flask(__name__)
ALLOWED_EXTENSIONS = {'jpg', 'jpeg'}
app.config['UPLOAD_FOLDER'] = 'static/images'
# Assemble plotter parts
db = Database("data.db")
cam = Camera()
ext = Extractor()
plotter = Plotter()
logger = logging.getLogger()
def setup():
'''
Start the server. Start logging with appropriate settings,
create required tables and initialize status if it doesn't exist
already. Executed always when server starts.
'''
setup_logger()
db.commit_query('''CREATE TABLE IF NOT EXISTS Status (id INTEGER, state TEXT)''')
db.commit_query('''CREATE TABLE IF NOT EXISTS Images (date DATE, name TEXT NOT NULL,
image BLOB NOT NULL)''')
db.init_state("Status")
def plot(image):
'''
Connects server to the plotter. Used whenever the user
initiates plotting.
:param image: Image to plot
:type image: str
'''
plotted = False
# Create image for plotting
img = db.retrieve_image("Images", image)
if img[0]:
with open('static/plot.jpg', 'wb') as file:
file.write(img[0])
# Prevent plot spamming
db.change_state("Status", "Busy")
ext.set_filepath('static/plot.jpg')
# Plot the image
plotter.plot(ext.get_contours())
db.change_state("Status", "Idle")
plotted = True
return plotted
@app.route("/", methods=["GET"])
def home():
'''Main view, with redirections to all subpages.'''
return render_template("home.html")
@app.route("/plot", methods=["GET", "POST"])
def plot_page():
'''View for plotting images using plotter.'''
# GET
if request.method == "GET":
return render_template("plot.html")
# POST
try:
plotting = db.get_state("Status")
# Do not plot if the plotter is already plotting or an error
# has occured
if plotting == "Idle":
data = json.loads(request.data.decode("utf-8"))
exists = db.image_exists(data['image'], 'Images')
if exists:
if plot(data['image']):
return jsonify({"message": "Image plotted."}), 200
return jsonify({"message": "Cannot plot imagge."}), 403
return jsonify({"message": "Image does not exist"}), 404
return jsonify({'message': 'Plotter is busy.'}), 403
except Exception as err:
logger.error("Error while plotting an image: %s", err)
return jsonify({"message": "Unable to plot image"}), 403
@app.route("/camera", methods=["GET", "POST"])
def take_picture():
'''View for taking pictures with piCamera.'''
# GET
if request.method == "GET":
return render_template("camera.html")
# POST
try:
cam.take_picture()
db.store_image("static/cam.jpg", "Images",
"cam" + datetime.now().strftime("-%d-%m-%Y-%H-%M-%S") + ".jpg")
return jsonify({'message': 'Picture taken successfully.'}), 201
except Exception as err:
logger.error("Error while taking a picture: %s", err)
return jsonify({'message': 'Problem with camera'}), 403
@app.route("/images", methods=["GET", "POST"])
def images():
'''View for browsing images in the database.'''
if request.method == "GET":
return render_template("images.html")
# POST
try:
return jsonify({'images': db.get_images("images")}), 200
except KeyError:
return jsonify({'message': 'Request in incorrect format'}), 401
@app.route("/images/<string:name>", methods=["GET", "DELETE"])
def get_image(name):
'''
This view will generate local file with the image from the database.
It also enables the user to delete images in the database.
:param name: name of the image
:type name: str
'''
if request.method == "GET":
img = db.retrieve_image("images", name)
if img[0]:
with open('static/res.jpg', 'wb') as file:
file.write(img[0])
return jsonify({"message": "Image retrieved."}), 200
# DELETE
try:
removed = db.remove_image("images", name)
if removed:
return jsonify({"message": "Image removed."}), 200
return jsonify({"message": "Unable to remove image."}), 403
except Exception as ex:
logger.error("Error while removing image %s : %s", name, ex)
return jsonify({"message": "Unable to remove image."}), 403
@app.route("/display")
def display_image():
'''View for displaying the already generated image.'''
return redirect(url_for('static', filename="res.jpg"), code=301)
@app.route("/upload", methods=["GET", "POST"])
def upload_image():
'''View for uploading images to the database.'''
if request.method == "POST":
if 'img-file' not in request.files:
return jsonify({"message": "No image provided."}), 401
file = request.files['img-file']
# If no file is specified, browsers send empty files
if file == '':
return jsonify({"message": "No image provided."}), 401
# Image must have an extension
if file and '.' in file.filename:
# Only jpg files are supported
if "jpg" in file.filename.rsplit('.', 1)[1].lower():
file.save(os.path.join(app.config['UPLOAD_FOLDER'], "input.jpg"))
db.store_image(os.path.join(app.config['UPLOAD_FOLDER'], "input.jpg"), "images",
file.filename)
return jsonify({"message": "Image uploaded."}), 200
return jsonify({"message": "Image is not a jpg."}), 401
return jsonify({"message": "File is not an image."}), 401
return render_template("upload.html")
@app.route("/stats/status", methods=["GET"])
def get_status():
'''View for getting plotter status.'''
try:
status = db.get_state("Status")
return jsonify({"message": status}), 200
except Exception as err:
logger.error("Error while getting status : %s", err)
return jsonify({"message": "Error"}), 200
@app.route("/stats/logs", methods=["GET"])
def get_logs():
'''View for downloading plotter logs.'''
try:
return send_file("plotter.log", as_attachment=True)
except Exception as err:
logger.error("Error while sending logs : %s", err)
return jsonify({"message": "Unable to send logs"}), 403
@app.route("/stats", methods=["GET"])
def get_stats():
'''View for retrieving statistics about plotter.'''
return render_template("stats.html")
if __name__ == "__main__":
logger.debug("Setting up the server...")
plotter.pen_up()
setup()
logger.info("Server ready to work!")
app.logger.setLevel(logging.INFO)
app.run(debug=False, port=5000, host='0.0.0.0')