From 5dd0694a989bfc63f3c3c688fa18662bfb93e3d7 Mon Sep 17 00:00:00 2001 From: Reid D McKenzie Date: Tue, 28 Jan 2025 00:08:22 -0700 Subject: [PATCH] Bring bed leveling inboard --- projects/tentacles/src/tentacles/__main__.py | 3 +- projects/tentacles/src/tentacles/db.py | 2 +- projects/tentacles/src/tentacles/sql/jobs.sql | 11 +++++++ .../tentacles/src/tentacles/sql/printers.sql | 13 +++++++++ .../src/tentacles/static/css/style.scss | 8 +++++ .../tentacles/templates/files_list.html.j2 | 2 +- .../src/tentacles/templates/jobs_list.html.j2 | 23 +++++++++------ projects/tentacles/src/tentacles/workers.py | 29 +++++++++++++++++-- 8 files changed, 76 insertions(+), 15 deletions(-) diff --git a/projects/tentacles/src/tentacles/__main__.py b/projects/tentacles/src/tentacles/__main__.py index ddd310f..09bd9b0 100644 --- a/projects/tentacles/src/tentacles/__main__.py +++ b/projects/tentacles/src/tentacles/__main__.py @@ -2,7 +2,7 @@ """The core app entrypoint.""" -from datetime import datetime +from datetime import datetime, timedelta import logging from pathlib import Path import tomllib @@ -46,6 +46,7 @@ def create_j2_request_global(app): app.jinja_env.globals["ctx"] = ctx app.jinja_env.globals["request"] = request app.jinja_env.globals["datetime"] = datetime + app.jinja_env.globals["timedelta"] = timedelta def user_session(): diff --git a/projects/tentacles/src/tentacles/db.py b/projects/tentacles/src/tentacles/db.py index 4c45767..a374296 100644 --- a/projects/tentacles/src/tentacles/db.py +++ b/projects/tentacles/src/tentacles/db.py @@ -21,7 +21,7 @@ from aiosql.query_loader import QueryLoader _sqlite = get_adapter("sqlite3") _loader = QueryLoader(_sqlite, None) -_queries = Queries(_sqlite) +_queries = Queries(_sqlite, kwargs_only=False) for f in files("tentacles.sql").iterdir(): if f.is_file() and f.name.endswith(".sql"): print("Loading", f) diff --git a/projects/tentacles/src/tentacles/sql/jobs.sql b/projects/tentacles/src/tentacles/sql/jobs.sql index 0eba47c..0705964 100644 --- a/projects/tentacles/src/tentacles/sql/jobs.sql +++ b/projects/tentacles/src/tentacles/sql/jobs.sql @@ -26,6 +26,9 @@ CREATE TABLE IF NOT EXISTS jobs ( , FOREIGN KEY(printer_id) REFERENCES printer(id) ); +-- name: migration-0001-jobs-add-print-time# +ALTER TABLE jobs ADD COLUMN time_left INTEGER DEFAULT (0); + -- name: create-job^ INSERT INTO jobs ( user_id @@ -81,6 +84,7 @@ SELECT , (SELECT name FROM filament WHERE id = fa.filament_id) AS filament_name , (SELECT name FROM job_statuses WHERE id = j.status_id) AS status , j.started_at + , j.time_left , j.cancelled_at , j.finished_at , j.user_id @@ -220,3 +224,10 @@ UPDATE jobs WHERE id = :jid ; + +-- name: update-job-time-left! +UPDATE jobs + SET time_left = :time_left +WHERE + id = :jid +; diff --git a/projects/tentacles/src/tentacles/sql/printers.sql b/projects/tentacles/src/tentacles/sql/printers.sql index 054ad19..ae31f77 100644 --- a/projects/tentacles/src/tentacles/sql/printers.sql +++ b/projects/tentacles/src/tentacles/sql/printers.sql @@ -78,6 +78,9 @@ ALTER TABLE printers ADD enabled BOOLEAN DEFAULT TRUE; -- name: migration-0005-create-printer-nozzle# ALTER TABLE printers ADD nozzle_diameter FLOAT DEFAULT 0.4; +-- name: migration-0006-create-printer-level-date# +ALTER TABLE printers ADD last_level_date TEXT DEFAULT NULL; + -- name: try-create-printer^ INSERT INTO printers ( name @@ -98,6 +101,7 @@ SELECT , p.stream_url , p.api_key , p.last_poll_date + , p.last_level_date , p.filament_id , p.chassis_id , p.enabled @@ -116,6 +120,7 @@ SELECT , p.stream_url , p.api_key , p.last_poll_date + , p.last_level_date , s.name as status , p.enabled , f.name as filament_name @@ -166,6 +171,14 @@ WHERE id = :pid ; +-- name: update-printer-level-date! +UPDATE printers +SET + , last_level_date = datetime('now') +WHERE + id = :pid +; + -- name: edit-printer! UPDATE printers SET diff --git a/projects/tentacles/src/tentacles/static/css/style.scss b/projects/tentacles/src/tentacles/static/css/style.scss index 16ae715..d3f6518 100644 --- a/projects/tentacles/src/tentacles/static/css/style.scss +++ b/projects/tentacles/src/tentacles/static/css/style.scss @@ -22,6 +22,14 @@ margin-top: 4px; } +.div .job { + +} + +.div .job:not(:last-child) { + border-bottom: none; +} + .file .details, .printer .details, .key .details, diff --git a/projects/tentacles/src/tentacles/templates/files_list.html.j2 b/projects/tentacles/src/tentacles/templates/files_list.html.j2 index ef907d8..283bce6 100644 --- a/projects/tentacles/src/tentacles/templates/files_list.html.j2 +++ b/projects/tentacles/src/tentacles/templates/files_list.html.j2 @@ -25,8 +25,8 @@ {% endif %}
- {{ macros.start_job(file.id) }} {{ macros.download_file(file.id) }} + {{ macros.start_job(file.id) }} {{ macros.delete_file(file.id) }}
diff --git a/projects/tentacles/src/tentacles/templates/jobs_list.html.j2 b/projects/tentacles/src/tentacles/templates/jobs_list.html.j2 index 7400b5e..8241e45 100644 --- a/projects/tentacles/src/tentacles/templates/jobs_list.html.j2 +++ b/projects/tentacles/src/tentacles/templates/jobs_list.html.j2 @@ -10,18 +10,24 @@ {{ctx.db.fetch_file(ctx.uid, job.file_id).filename or "it's a secret"}} {% if job.printer_id %} -
+
{{ ctx.db.fetch_printer(job.printer_id).name }}
{% endif %} {% if job.started_at %} -
- - {{ (datetime.utcnow() - datetime.fromisoformat(job.started_at)) }} -
- {% else %} -
+
+ + {{ (datetime.utcnow() - datetime.fromisoformat(job.started_at)) }} +
+ {% endif %} + {% if job.time_left > 0 %} +
+ + {{ timedelta(seconds=job.time_left) }} +
+ {% endif %} +
{{ job.filament_name }}
@@ -29,7 +35,6 @@ {{ job.max_x }}mm x{{ job.max_y }}mm x{{ job.max_z }}mm, bed {{ job.max_bed }}c, end {{ job.max_end }}c, nozzle {{ "%.2f"|format(job.nozzle_diameter) }}mm
- {% endif %} {% if job.user_id != ctx.uid %}
@@ -37,7 +42,7 @@
{% endif %}
-
+
diff --git a/projects/tentacles/src/tentacles/workers.py b/projects/tentacles/src/tentacles/workers.py index 27f9335..6563cdc 100644 --- a/projects/tentacles/src/tentacles/workers.py +++ b/projects/tentacles/src/tentacles/workers.py @@ -89,10 +89,12 @@ def poll_printers(app: App, db: Db) -> None: ) if "error" in status: - log.error(f"Printer {printer.id} failed to report bed readiness with {status!r}") + log.error( + f"Printer {printer.id} failed to report bed readiness with {status!r}" + ) return False - - similarity = status.get("similarity", 0.0) ** 3 # Cube it + + similarity = status.get("similarity", 0.0) ** 3 # Cube it return similarity > 0.9 printer_job = {} @@ -216,6 +218,21 @@ def push_jobs(app: App, db: Db) -> None: else: raise + # FIXME: Time since last job ended? + if last_level_date := printer.last_level_date: + last_level_date = datetime.fromisoformat(last_level_date) + + if not last_level_date or ( + datetime.utcnow() - last_level_date >= timedela(hours=24) + ): + log.info(f"Printer {printer.id} needs to be leveled...") + client.gcode( + [ + "G29", + ] + ) + db.update_printer_level_date(pid=printer.id) + client.select(Path(file.path).name) client.start() db.start_job(jid=job.id) @@ -275,6 +292,12 @@ def pull_jobs(app: App, db: Db) -> None: log.info(f"Job {job.id} has succeeded") db.finish_job(jid=job.id, state="success") + elif job_state.get("progress", {}).get("completion", 0.0) < 100.0: + time_left = float( + job_state.get("progress", {}).get("printTimeLeft", "3600.0") + ) + db.update_job_time_left(jid=job.id, time_left=time_left) + elif printer_state.get("error"): log.warn(f"Job {job.id} has failed") db.finish_job(jid=job.id, state="failed")