From 586c585980107b9e79c1548a61ff472a9be7b96a Mon Sep 17 00:00:00 2001 From: Thomas Forgione Date: Wed, 17 Jul 2024 16:51:56 +0200 Subject: [PATCH] Working on acquisition --- app.py | 92 +++++++++++++++++++++++++++-- db.py | 77 ++++++++++++++++-------- schema.sql | 2 + templates/calibrate.html | 2 - templates/object.html | 21 ++++++- templates/scan.html | 124 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 285 insertions(+), 33 deletions(-) create mode 100644 templates/scan.html diff --git a/app.py b/app.py index c47d513..eb01279 100755 --- a/app.py +++ b/app.py @@ -6,6 +6,7 @@ import os from os.path import join import sqlite3 import uuid +from typing import Optional from . import db, config, scanner, calibration app = Flask(__name__) @@ -33,7 +34,7 @@ def get_calibration(conn: sqlite3.Connection) -> db.Calibration: @app.context_processor def inject_stage_and_region(): conn = db.get() - return dict(calibration=get_calibration(conn), CalibrationState=db.CalibrationState) + return dict(calibration=get_calibration(conn), leds=config.LEDS_UUIDS, CalibrationState=db.CalibrationState) @app.before_request @@ -63,15 +64,33 @@ def create_object(): @app.route('/object/') def object(id: int): conn = db.get() - object = db.Object.get_from_id(id, conn) + object = db.Object.get_from_id(id, conn).full(conn) return render_template('object.html', object=object) @app.route('/scan/') def scan(id: int): conn = db.get() + calibration_id = session.get('calibration_id', None) object = db.Object.get_from_id(id, conn) - return render_template('object.html', object=object) + + if calibration_id is None: + raise RuntimeError("Impossible de faire l'acquisition sans étalonnage") + + return render_template('scan.html', object=object) + + +@app.route('/scan-acquisition/') +def scan_existing(id: int): + conn = db.get() + calibration_id = session.get('calibration_id', None) + acquisition = db.Acquisition.get_from_id(id, conn) + object = acquisition.object(conn) + + if calibration_id is None: + raise RuntimeError("Impossible de faire l'acquisition sans étalonnage") + + return render_template('scan.html', object=object, acquisition=acquisition) @app.route("/calibrate/") @@ -85,7 +104,7 @@ def calibrate(): calibration = db.Calibration.get_from_id(session['calibration_id'], conn) if calibration.state in [db.CalibrationState.Empty, db.CalibrationState.HasData]: - return render_template('calibrate.html', leds=config.LEDS_UUIDS) + return render_template('calibrate.html') else: return render_template('calibration.html', calibration=calibration) @@ -146,6 +165,71 @@ def scan_calibration(): return app.response_class(generate(), mimetype='text/plain') +@app.route("/api/scan-for-object/") +def scan_object(object_id: int): + conn = db.get() + calibration_id = session.get('calibration_id', None) + + if calibration_id is None: + raise RuntimeError("Impossible de faire l'acquisition sans étalonnage") + + object = db.Object.get_from_id(object_id, conn) + + if object is None: + raise RuntimeError(f"Aucun objet d'id {object_id}") + + with conn: + acquisition = object.add_acquisition(calibration_id, conn) + + def generate(): + yield str(acquisition.id) + length = len(config.LEDS_UUIDS) + for index, led_uuid in enumerate(scanner.scan(join(config.OBJECT_DIR, str(object.id), str(acquisition.id)))): + yield f"{led_uuid},{(index+1)/length}\n" + + return app.response_class(generate(), mimetype='text/plain') + + +@app.route("/api/scan-for-acquisition/") +def scan_acquisition(acquisition_id: int): + conn = db.get() + calibration_id = session.get('calibration_id', None) + + if calibration_id is None: + raise RuntimeError("Impossible de faire l'acquisition sans étalonnage") + + acquisition = db.Acquisition.get_from_id(acquisition_id, conn) + + if acquisition is None: + raise RuntimeError(f"Aucun acquisition d'id {acquisition_id}") + + object = acquisition.object(conn) + + def generate(): + length = len(config.LEDS_UUIDS) + for index, led_uuid in enumerate(scanner.scan(join(config.OBJECT_DIR, str(object.id), str(acquisition.id)))): + yield f"{led_uuid},{(index+1)/length}\n" + + return app.response_class(generate(), mimetype='text/plain') + + +@app.route("/validate-acquisition/") +def validate_acquisition(acquisition_id: int): + conn = db.get() + acquisition = db.Acquisition.get_from_id(acquisition_id, conn) + + if acquisition is None: + raise f"Aucune acquisition d'id {acquisition_id}" + + object = acquisition.object(conn) + + acquisition.validated = True + with conn: + acquisition.save(conn) + + return redirect(f'/object/{object.id}') + + @app.route('/api/use-last-calibration') def use_last_calibration(): conn = db.get() diff --git a/db.py b/db.py index a3f3bdd..9004f9c 100755 --- a/db.py +++ b/db.py @@ -128,18 +128,20 @@ Calibration.Dummy = Calibration(-1, CalibrationState.Empty, None) class Acquisition: @staticmethod def select_args() -> str: - return 'id, calibration_id, object_id' + return 'id, calibration_id, object_id, date, validated' - def __init__(self, acquisition_id: int, calibration_id: int, object_id: int): - self.id = object_id + def __init__(self, acquisition_id: int, calibration_id: int, object_id: int, date: int, validated: int): + self.id = acquisition_id self.calibration_id = calibration_id self.object_id = object_id + self.date = datetime.fromtimestamp(date) + self.validated = validated != 0 def save(self, db: sqlite3.Connection): cur = db.cursor() cur.execute( - 'UPDATE acquisition SET calibration_id = ?, object_id = ? WHERE id = ?', - [self.calibration_id, self.object_id, self.id] + 'UPDATE acquisition SET calibration_id = ?, object_id = ?, date = ?, validated = ? WHERE id = ?', + [self.calibration_id, self.object_id, self.date.timestamp(), 1 if self.validated else 0, self.id] ) @staticmethod @@ -163,6 +165,19 @@ class Acquisition: return Calibration.get_from_id(self.calibration_id, db) + def object(self, db: sqlite3.Connection) -> 'Object': + return Object.get_from_id(self.object_id, db) + + def get_pretty_date(self) -> str: + return dateutils.format(self.date) + + +class FullObject: + def __init__(self, object_id: int, name: str, acquisitions: list[Acquisition]): + self.id = object_id + self.name = name + self.acquisitions = acquisitions + class Object: @staticmethod @@ -218,11 +233,21 @@ class Object: def add_acquisition(self, calibration_id: int, db: sqlite3.Connection) -> Acquisition: cur = db.cursor() response = cur.execute( - 'INSERT INTO acquisition(calibration_id, object_id) VALUES (?, ?) RETURNING ' + Acquisition.select_args() + ';', - [calibration_id, self.id] + 'INSERT INTO acquisition(calibration_id, object_id, date, validated) VALUES (?, ?, ?, ?) RETURNING ' + Acquisition.select_args() + ';', + [calibration_id, self.id, datetime.now().timestamp(), 0] ) return Acquisition.from_row(response.fetchone()) + def full(self, db: sqlite3.Connection) -> FullObject: + cur = db.cursor() + response = cur.execute( + 'SELECT ' + Acquisition.select_args() + ' FROM acquisition WHERE object_id = ? ORDER BY date DESC;', + [self.id] + ) + acquisitions = list(map(lambda x: Acquisition.from_row(x), response.fetchall())) + print(acquisitions) + return FullObject(self.id, self.name, acquisitions) + def main(): # Move current data to backup dir @@ -245,26 +270,26 @@ def main(): init(db) # Create a new object - with db: - Object.create('Mon premier objet', db) - # calibration = Calibration.create(db) - # object.add_acquisition(calibration.id, db) - # object.add_acquisition(calibration.id, db) - # object.add_acquisition(calibration.id, db) - # calibration = Calibration.create(db) - # object.add_acquisition(calibration.id, db) - # object.add_acquisition(calibration.id, db) - # object.add_acquisition(calibration.id, db) + # with db: + # Object.create('Mon premier objet', db) + # # calibration = Calibration.create(db) + # # object.add_acquisition(calibration.id, db) + # # object.add_acquisition(calibration.id, db) + # # object.add_acquisition(calibration.id, db) + # # calibration = Calibration.create(db) + # # object.add_acquisition(calibration.id, db) + # # object.add_acquisition(calibration.id, db) + # # object.add_acquisition(calibration.id, db) - Object.create('Mon deuxième objet', db) - # calibration = Calibration.create(db) - # object.add_acquisition(calibration.id, db) - # object.add_acquisition(calibration.id, db) - # object.add_acquisition(calibration.id, db) - # calibration = Calibration.create(db) - # object.add_acquisition(calibration.id, db) - # object.add_acquisition(calibration.id, db) - # object.add_acquisition(calibration.id, db) + # Object.create('Mon deuxième objet', db) + # # calibration = Calibration.create(db) + # # object.add_acquisition(calibration.id, db) + # # object.add_acquisition(calibration.id, db) + # # object.add_acquisition(calibration.id, db) + # # calibration = Calibration.create(db) + # # object.add_acquisition(calibration.id, db) + # # object.add_acquisition(calibration.id, db) + # # object.add_acquisition(calibration.id, db) if __name__ == '__main__': diff --git a/schema.sql b/schema.sql index bbad611..ed7595b 100644 --- a/schema.sql +++ b/schema.sql @@ -12,6 +12,8 @@ CREATE TABLE acquisition ( id INTEGER PRIMARY KEY AUTOINCREMENT, calibration_id INTEGER NOT NULL, object_id INTEGER NOT NULL, + date INTEGER NOT NULL, + validated INT NOT NULL, CONSTRAINT fk_calibration FOREIGN KEY(calibration_id) REFERENCES calibration(id), CONSTRAINT fk_object FOREIGN KEY(object_id) REFERENCES object(id) ); diff --git a/templates/calibrate.html b/templates/calibrate.html index b3d3ca6..d17f5c9 100644 --- a/templates/calibrate.html +++ b/templates/calibrate.html @@ -33,7 +33,6 @@

Si les données d'étalonnage conviennent, appuyez sur le bouton ci-dessous pour procéder à l'étalonnage du scanner.

-

@@ -53,7 +52,6 @@ let errorContent = document.getElementById('error-content'); let calibrateDiv = document.getElementById('calibrate'); let calibrateButton = document.getElementById('calibrate-button'); - let calibrationInfo = document.getElementById('calibration-info'); previewButton.addEventListener('click', async () => { buttons.forEach(x => x.setAttribute('disabled', 'disabled')); diff --git a/templates/object.html b/templates/object.html index c98ef90..614158e 100644 --- a/templates/object.html +++ b/templates/object.html @@ -2,8 +2,27 @@ {% block content %}
-
+

{{ object.name }}

+ {% if object.acquisitions %} +
+
+ {% for acquisition in object.acquisitions %} + +
+
+ +
+

+ {{ acquisition.get_pretty_date() }} +

+
+
+ {% endfor %} +
+
+ {% endif %} + {% if calibration.state == CalibrationState.IsValidated %} Faire un scan {% else %} diff --git a/templates/scan.html b/templates/scan.html new file mode 100644 index 0000000..38064bd --- /dev/null +++ b/templates/scan.html @@ -0,0 +1,124 @@ +{% extends "base.html" %} + +{% block content %} +
+
+

Faire une acquisition

+
+

Placez l'objet devant le scanner puis appuyez sur le bouton pour lancer l'acquisition.

+
+
+
+ +
+
+ +
+
+ +
+
+ +
+

Si les données acquises conviennent, appuyez sur le bouton ci-dessous pour valider l'acquisition.

+ {% if acquisition %} + {% if acquisition.validated %} + + {% else %} + Valider l'acquisition + {% endif %} + {% else %} + Valider l'acquisition + {% endif %} +
+
+
+{% endblock content %} + +{% block extrajs %} + +{% endblock extrajs %}