Working
This commit is contained in:
parent
b1ddbe23ee
commit
f6f34d6260
|
|
@ -1,7 +1,7 @@
|
|||
db.sqlite
|
||||
.device
|
||||
data
|
||||
data-keep
|
||||
data-*
|
||||
secret.py
|
||||
node_modules
|
||||
static/calibration-visualiser.*
|
||||
|
||||
|
|
|
|||
61
app.py
61
app.py
|
|
@ -9,7 +9,17 @@ import uuid
|
|||
from . import db, config, scanner, calibration
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config['SECRET_KEY'] = os.urandom(20).hex()
|
||||
|
||||
# Manage secret key
|
||||
try:
|
||||
from . import secret
|
||||
app.config['SECRET_KEY'] = secret.SECRET_KEY
|
||||
except ImportError:
|
||||
# Secret key file does not exist, create it
|
||||
secret = os.urandom(50).hex()
|
||||
with open('secret.py', 'w') as f:
|
||||
f.write(f'SECRET_KEY = "{secret}"')
|
||||
app.config['SECRET_KEY'] = secret
|
||||
|
||||
|
||||
def get_calibration(conn: sqlite3.Connection) -> db.Calibration:
|
||||
|
|
@ -51,19 +61,45 @@ def object(id: int):
|
|||
@app.route('/scan/<id>')
|
||||
def scan(id: int):
|
||||
conn = db.get()
|
||||
print(session)
|
||||
object = db.Object.get_from_id(id, conn)
|
||||
return render_template('object.html', object=object)
|
||||
|
||||
|
||||
@app.route("/calibrate/")
|
||||
def calibrate():
|
||||
print(session)
|
||||
conn = db.get()
|
||||
if 'calibration_id' not in session:
|
||||
with conn:
|
||||
calibration = db.Calibration.create(conn)
|
||||
session['calibration_id'] = calibration.id
|
||||
else:
|
||||
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)
|
||||
else:
|
||||
return render_template('calibration.html', calibration=calibration)
|
||||
|
||||
|
||||
@app.route("/new-calibration")
|
||||
def new_calibration():
|
||||
conn = db.get()
|
||||
with conn:
|
||||
calibration = db.Calibration.create(conn)
|
||||
session['calibration_id'] = calibration.id
|
||||
|
||||
return redirect('/calibrate')
|
||||
|
||||
|
||||
@app.route("/cancel-calibration")
|
||||
def cancel_calibration():
|
||||
conn = db.get()
|
||||
calibration = db.Calibration.get_from_id(session['calibration_id'], conn)
|
||||
calibration.state = db.CalibrationState.HasData
|
||||
with conn:
|
||||
calibration.save(conn)
|
||||
return redirect('/calibrate')
|
||||
|
||||
|
||||
@app.route("/api/preview/<id>")
|
||||
|
|
@ -102,9 +138,19 @@ def scan_calibration():
|
|||
return app.response_class(generate(), mimetype='text/plain')
|
||||
|
||||
|
||||
@app.route("/api/calibrate/<id>")
|
||||
def run_calibration(id: int):
|
||||
@app.route('/api/use-last-calibration')
|
||||
def use_last_calibration():
|
||||
conn = db.get()
|
||||
calibration = db.Calibration.get_last(conn)
|
||||
session['calibration_id'] = calibration.id
|
||||
print(session);
|
||||
return 'ok'
|
||||
|
||||
|
||||
@app.route("/api/calibrate")
|
||||
def run_calibration():
|
||||
conn = db.get()
|
||||
id = session['calibration_id']
|
||||
calib = db.Calibration.get_from_id(id, conn)
|
||||
if calib is None:
|
||||
return 'oops', 404
|
||||
|
|
@ -133,13 +179,6 @@ def validate_calibration():
|
|||
return redirect('/')
|
||||
|
||||
|
||||
@app.route("/calibration/<id>")
|
||||
def calibration_page(id: int):
|
||||
conn = db.get()
|
||||
calibration = db.Calibration.get_from_id(id, conn)
|
||||
return render_template('calibration.html', calibration=calibration)
|
||||
|
||||
|
||||
@app.route('/static/<path:path>')
|
||||
def send_static(path):
|
||||
return send_from_directory('static', path)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ def print_error(msg: str):
|
|||
|
||||
def calibrate(input_dir: str):
|
||||
# Load all images
|
||||
image_names = sorted(os.listdir(input_dir))
|
||||
image_names = list(filter(lambda x: x != 'calibration.json', sorted(os.listdir(input_dir))))
|
||||
images = [np.asarray(Image.open(os.path.join(input_dir, x))) for x in image_names]
|
||||
|
||||
# Camera parameters
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
from os.path import join
|
||||
|
||||
MODE = 'debug'
|
||||
DATA_DIR = 'data'
|
||||
BACKUPS_DIR = 'data-backups'
|
||||
CALIBRATION_DIR = join(DATA_DIR, 'calibrations')
|
||||
OBJECT_DIR = join(DATA_DIR, 'objects')
|
||||
DATABASE_PATH = join(DATA_DIR, 'db.sqlite')
|
||||
SECRET_KEY = 'tobedefined'
|
||||
|
||||
LEDS_UUIDS = [
|
||||
'ac59350e-3787-46d2-88fa-743c1d34fe86',
|
||||
|
|
|
|||
47
db.py
47
db.py
|
|
@ -1,12 +1,12 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from enum import IntEnum
|
||||
from datetime import datetime
|
||||
from flask import g
|
||||
import os
|
||||
from os.path import join
|
||||
import shutil
|
||||
import sqlite3
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
if __name__ != '__main__':
|
||||
|
|
@ -18,7 +18,7 @@ else:
|
|||
def get() -> sqlite3.Connection:
|
||||
if 'db' not in g:
|
||||
g.db = sqlite3.connect(
|
||||
os.environ.get('DATABASE_PATH', 'db.sqlite'),
|
||||
config.DATABASE_PATH,
|
||||
detect_types=sqlite3.PARSE_DECLTYPES,
|
||||
)
|
||||
g.db.row_factory = sqlite3.Row
|
||||
|
|
@ -69,11 +69,15 @@ class Calibration:
|
|||
[int(CalibrationState.Empty)]
|
||||
)
|
||||
calibration = Calibration.from_row(response.fetchone())
|
||||
if calibration is None:
|
||||
return None
|
||||
os.makedirs(join(config.CALIBRATION_DIR, str(calibration.id)))
|
||||
return calibration
|
||||
|
||||
@staticmethod
|
||||
def from_row(row: sqlite3.Row) -> 'Calibration':
|
||||
def from_row(row: Optional['sqlite3.Row']) -> Optional['Calibration']:
|
||||
if row is None:
|
||||
return None
|
||||
return Calibration(*row)
|
||||
|
||||
def save(self, db: sqlite3.Connection):
|
||||
|
|
@ -92,6 +96,15 @@ class Calibration:
|
|||
)
|
||||
return Calibration.from_row(response.fetchone())
|
||||
|
||||
@staticmethod
|
||||
def get_last(db: sqlite3.Connection) -> Optional['Calibration']:
|
||||
cur = db.cursor()
|
||||
response = cur.execute(
|
||||
'SELECT ' + Calibration.select_args() + ' FROM calibration WHERE state = 3 ORDER BY id DESC LIMIT 1;',
|
||||
[]
|
||||
)
|
||||
return Calibration.from_row(response.fetchone())
|
||||
|
||||
|
||||
Calibration.Dummy = Calibration(-1, CalibrationState.Empty)
|
||||
|
||||
|
|
@ -114,7 +127,9 @@ class Acquisition:
|
|||
)
|
||||
|
||||
@staticmethod
|
||||
def from_row(row: sqlite3.Row) -> 'Acquisition':
|
||||
def from_row(row: Optional[sqlite3.Row]) -> Optional['Acquisition']:
|
||||
if row is None:
|
||||
return None
|
||||
return Acquisition(*row)
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -150,7 +165,9 @@ class Object:
|
|||
)
|
||||
|
||||
@staticmethod
|
||||
def from_row(row: sqlite3.Row) -> 'Object':
|
||||
def from_row(row: Optional[sqlite3.Row]) -> Optional['Object']:
|
||||
if row is None:
|
||||
return None
|
||||
return Object(*row)
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -192,20 +209,25 @@ class Object:
|
|||
|
||||
|
||||
def main():
|
||||
if config.MODE != 'debug':
|
||||
print('Can only reset db in debug mode')
|
||||
sys.exit(1)
|
||||
# Move current data to backup dir
|
||||
if os.path.isdir(config.DATA_DIR):
|
||||
# Ensure backup dir exists
|
||||
os.makedirs(config.BACKUPS_DIR, exist_ok=True)
|
||||
|
||||
now = datetime.now()
|
||||
dest = join(config.BACKUPS_DIR, f'{now.year}-{now.month:02}-{now.day:02}--{now.hour:02}-{now.minute:02}-{now.second:02}')
|
||||
shutil.move(config.DATA_DIR, dest)
|
||||
|
||||
# Create new empty data dir
|
||||
os.makedirs(config.DATA_DIR, exist_ok=True)
|
||||
|
||||
db = sqlite3.connect(
|
||||
os.environ.get('DATABASE_PATH', 'db.sqlite'),
|
||||
config.DATABASE_PATH,
|
||||
detect_types=sqlite3.PARSE_DECLTYPES,
|
||||
)
|
||||
db.row_factory = sqlite3.Row
|
||||
init(db)
|
||||
|
||||
if os.path.isdir(config.DATA_DIR):
|
||||
shutil.rmtree(config.DATA_DIR)
|
||||
|
||||
# Create a new object
|
||||
with db:
|
||||
Object.create('Mon premier objet', db)
|
||||
|
|
@ -230,5 +252,4 @@ def main():
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) > 1 and sys.argv[1] == 'reset':
|
||||
main()
|
||||
|
|
|
|||
|
|
@ -22,30 +22,30 @@
|
|||
</div>
|
||||
<div id="navbarBasicExample" class="navbar-menu">
|
||||
<div class="navbar-end">
|
||||
<a id="calibration-tag-0" class="calibration-tag navbar-item" href="#" {% if calibration.state != 0 %}style="display: none;"{% endif %}>
|
||||
<a id="calibration-tag-0" class="calibration-tag navbar-item" href="/calibrate/" {% if calibration.state != 0 %}style="display: none;"{% endif %}>
|
||||
<span id="calibration-tag-0" class="tags has-addons">
|
||||
<span class="tag is-dark">étalonnage</span>
|
||||
<span class="tag is-danger">aucune donnée</span>
|
||||
</span>
|
||||
</a>
|
||||
<a id="calibration-tag-1" class="calibration-tag navbar-item" href="#" {% if calibration.state != 1 %}style="display: none;"{% endif %}>
|
||||
<a id="calibration-tag-1" class="calibration-tag navbar-item" href="/calibrate/" {% if calibration.state != 1 %}style="display: none;"{% endif %}>
|
||||
<span class="tags has-addons" >
|
||||
<span class="tag is-dark">étalonnage</span>
|
||||
<span class="tag is-warning">non calculé</span>
|
||||
</span>
|
||||
</a>
|
||||
<a id="calibration-tag-2" class="calibration-tag navbar-item" href="#" {% if calibration.state != 2 %}style="display: none;"{% endif %}>
|
||||
<a id="calibration-tag-2" class="calibration-tag navbar-item" href="/calibrate/" {% if calibration.state != 2 %}style="display: none;"{% endif %}>
|
||||
<span class="tags has-addons">
|
||||
<span class="tag is-dark">étalonnage</span>
|
||||
<span class="tag is-warning">non validé</span>
|
||||
</span>
|
||||
</a>
|
||||
<span id="calibration-tag-3" class="calibration-tag navbar-item" href="#" {% if calibration.state != 3 %}style="display: none;"{% endif %}>
|
||||
<span, class="tags has-addons">
|
||||
<a id="calibration-tag-3" class="calibration-tag navbar-item" href="/calibrate" {% if calibration.state != 3 %}style="display: none;"{% endif %}>
|
||||
<span class="tags has-addons">
|
||||
<span class="tag is-dark">étalonnage</span>
|
||||
<span class="tag is-success">validé</span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -131,8 +131,8 @@
|
|||
calibrateButton.addEventListener('click', async () => {
|
||||
calibrateButton.classList.add('is-loading');
|
||||
|
||||
await fetch('/api/calibrate/{{ calibration.id }}');
|
||||
window.location.href = '/calibration/{{ calibration.id }}';
|
||||
await fetch('/api/calibrate');
|
||||
window.location.reload();
|
||||
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<div class="column">
|
||||
<h2 class="title is-3">Vue de la LED selectionnée</h2>
|
||||
<div>
|
||||
<img id="led-view">
|
||||
<img id="led-view" style="width: 100%">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -41,13 +41,24 @@
|
|||
|
||||
<section>
|
||||
<div class="container">
|
||||
<div class="field is-grouped is-grouped-right">
|
||||
<div class="field is-horizontal is-grouped is-grouped-right">
|
||||
{% if calibration.state == CalibrationState.IsValidated %}
|
||||
<div class="control">
|
||||
<a href="/calibrate" class="button">Retourner à la page d'acquisition</a>
|
||||
<button disabled class="button">
|
||||
Cet étalonnage a déjà été validé
|
||||
</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a href="/new-calibration" class="button is-link">Créer un nouvel étalonnage</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="control">
|
||||
<a href="/cancel-calibration" class="button">Retourner à la page d'acquisition</a>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a href="/validate-calibration" class="button is-link">Valider l'étalonnage</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -77,5 +88,6 @@
|
|||
{% endblock extracss %}
|
||||
|
||||
{% block extrajs %}
|
||||
<script>window.CALIBRATION_ID = {{ calibration.id }};</script>
|
||||
<script src="/static/calibration-visualiser.js"></script>
|
||||
{% endblock extrajs %}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<a href="/calibrate/" class="button is-link">Étalonner le scanner</a>
|
||||
</div>
|
||||
<div class="control">
|
||||
<a href="/calibrate/" class="button is-link">Réutiliser le dernier étalonnage</a>
|
||||
<button id="use-last-calibration-button" href="/use-last-calibration/" class="button is-link">Réutiliser le dernier étalonnage</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -41,5 +41,10 @@
|
|||
modal.classList.remove('is-active');
|
||||
});
|
||||
});
|
||||
document.getElementById('use-last-calibration-button').addEventListener('click', async () => {
|
||||
let resp = await fetch('/api/use-last-calibration');
|
||||
await resp.text();
|
||||
window.location.href = '/scan/{{ object.id }}';
|
||||
});
|
||||
</script>
|
||||
{% endif %}{% endblock %}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,13 @@ function getImageElementById(id: string): HTMLImageElement {
|
|||
return element;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
/** This global variable must be set before including this script in the HTML page. */
|
||||
CALIBRATION_ID: number;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The class that manages the interface for the calibration visualisation.
|
||||
*/
|
||||
|
|
@ -105,7 +112,7 @@ export class Engine {
|
|||
|
||||
/** Initialises the engine. */
|
||||
static async create(domId: string) {
|
||||
let calibrationId = parseInt(window.location.pathname.split('/')[2], 10);
|
||||
let calibrationId = window.CALIBRATION_ID;
|
||||
|
||||
let domElement = getElementById(domId);
|
||||
let engine = new Engine();
|
||||
|
|
|
|||
Loading…
Reference in New Issue