Bring bed leveling inboard

This commit is contained in:
Reid D McKenzie 2025-01-28 00:08:22 -07:00
parent 81e60284c0
commit 5dd0694a98
8 changed files with 76 additions and 15 deletions

View file

@ -2,7 +2,7 @@
"""The core app entrypoint.""" """The core app entrypoint."""
from datetime import datetime from datetime import datetime, timedelta
import logging import logging
from pathlib import Path from pathlib import Path
import tomllib import tomllib
@ -46,6 +46,7 @@ def create_j2_request_global(app):
app.jinja_env.globals["ctx"] = ctx app.jinja_env.globals["ctx"] = ctx
app.jinja_env.globals["request"] = request app.jinja_env.globals["request"] = request
app.jinja_env.globals["datetime"] = datetime app.jinja_env.globals["datetime"] = datetime
app.jinja_env.globals["timedelta"] = timedelta
def user_session(): def user_session():

View file

@ -21,7 +21,7 @@ from aiosql.query_loader import QueryLoader
_sqlite = get_adapter("sqlite3") _sqlite = get_adapter("sqlite3")
_loader = QueryLoader(_sqlite, None) _loader = QueryLoader(_sqlite, None)
_queries = Queries(_sqlite) _queries = Queries(_sqlite, kwargs_only=False)
for f in files("tentacles.sql").iterdir(): for f in files("tentacles.sql").iterdir():
if f.is_file() and f.name.endswith(".sql"): if f.is_file() and f.name.endswith(".sql"):
print("Loading", f) print("Loading", f)

View file

@ -26,6 +26,9 @@ CREATE TABLE IF NOT EXISTS jobs (
, FOREIGN KEY(printer_id) REFERENCES printer(id) , 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^ -- name: create-job^
INSERT INTO jobs ( INSERT INTO jobs (
user_id user_id
@ -81,6 +84,7 @@ SELECT
, (SELECT name FROM filament WHERE id = fa.filament_id) AS filament_name , (SELECT name FROM filament WHERE id = fa.filament_id) AS filament_name
, (SELECT name FROM job_statuses WHERE id = j.status_id) AS status , (SELECT name FROM job_statuses WHERE id = j.status_id) AS status
, j.started_at , j.started_at
, j.time_left
, j.cancelled_at , j.cancelled_at
, j.finished_at , j.finished_at
, j.user_id , j.user_id
@ -220,3 +224,10 @@ UPDATE jobs
WHERE WHERE
id = :jid id = :jid
; ;
-- name: update-job-time-left!
UPDATE jobs
SET time_left = :time_left
WHERE
id = :jid
;

View file

@ -78,6 +78,9 @@ ALTER TABLE printers ADD enabled BOOLEAN DEFAULT TRUE;
-- name: migration-0005-create-printer-nozzle# -- name: migration-0005-create-printer-nozzle#
ALTER TABLE printers ADD nozzle_diameter FLOAT DEFAULT 0.4; 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^ -- name: try-create-printer^
INSERT INTO printers ( INSERT INTO printers (
name name
@ -98,6 +101,7 @@ SELECT
, p.stream_url , p.stream_url
, p.api_key , p.api_key
, p.last_poll_date , p.last_poll_date
, p.last_level_date
, p.filament_id , p.filament_id
, p.chassis_id , p.chassis_id
, p.enabled , p.enabled
@ -116,6 +120,7 @@ SELECT
, p.stream_url , p.stream_url
, p.api_key , p.api_key
, p.last_poll_date , p.last_poll_date
, p.last_level_date
, s.name as status , s.name as status
, p.enabled , p.enabled
, f.name as filament_name , f.name as filament_name
@ -166,6 +171,14 @@ WHERE
id = :pid id = :pid
; ;
-- name: update-printer-level-date!
UPDATE printers
SET
, last_level_date = datetime('now')
WHERE
id = :pid
;
-- name: edit-printer! -- name: edit-printer!
UPDATE printers UPDATE printers
SET SET

View file

@ -22,6 +22,14 @@
margin-top: 4px; margin-top: 4px;
} }
.div .job {
}
.div .job:not(:last-child) {
border-bottom: none;
}
.file .details, .file .details,
.printer .details, .printer .details,
.key .details, .key .details,

View file

@ -25,8 +25,8 @@
{% endif %} {% endif %}
</div> </div>
<div class="controls u-flex u-ml-auto u-mv-auto"> <div class="controls u-flex u-ml-auto u-mv-auto">
{{ macros.start_job(file.id) }}
{{ macros.download_file(file.id) }} {{ macros.download_file(file.id) }}
{{ macros.start_job(file.id) }}
{{ macros.delete_file(file.id) }} {{ macros.delete_file(file.id) }}
</div> </div>
</div> </div>

View file

@ -10,18 +10,24 @@
<span name="filename">{{ctx.db.fetch_file(ctx.uid, job.file_id).filename or "it's a secret"}}</span> <span name="filename">{{ctx.db.fetch_file(ctx.uid, job.file_id).filename or "it's a secret"}}</span>
</div> </div>
{% if job.printer_id %} {% if job.printer_id %}
<div class="job-printer u-flex"> <div class="job-printer u-flex u-flex-break">
<label for="printer">Printer</label> <label for="printer">Printer</label>
<span name="printer">{{ ctx.db.fetch_printer(job.printer_id).name }}</span> <span name="printer">{{ ctx.db.fetch_printer(job.printer_id).name }}</span>
</div> </div>
{% endif %} {% endif %}
{% if job.started_at %} {% if job.started_at %}
<div class="job-runtime u-flex"> <div class="job-runtime u-flex u-flex-break">
<label for="runtime">Runtime</label> <label for="runtime">Runtime</label>
<span name="Runtime">{{ (datetime.utcnow() - datetime.fromisoformat(job.started_at)) }}</span> <span name="Runtime">{{ (datetime.utcnow() - datetime.fromisoformat(job.started_at)) }}</span>
</div> </div>
{% else %} {% endif %}
<div class="job-constraint u-flex"> {% if job.time_left > 0 %}
<div class="job-remaining-time u-flex u-flex-break">
<label for="remaining-time">Remaining time</label>
<span name="remaining-time">{{ timedelta(seconds=job.time_left) }}</span>
</div>
{% endif %}
<div class="job-constraint u-flex u-flex-break">
<label>Material</label> <label>Material</label>
{{ job.filament_name }} {{ job.filament_name }}
</div> </div>
@ -29,7 +35,6 @@
<label>Limits</label> <label>Limits</label>
{{ 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 {{ 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
</div> </div>
{% endif %}
{% if job.user_id != ctx.uid %} {% if job.user_id != ctx.uid %}
<div class="job-user u-flex"> <div class="job-user u-flex">
<label>Owner</label> <label>Owner</label>
@ -37,7 +42,7 @@
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div class="two columns"> <div class="two columns u-mv-auto">
<div class="job-status u-flex"> <div class="job-status u-flex">
<label for="state">Status</label> <label for="state">Status</label>
<div class="dot {{ macros.job_state(job) }} {{ macros.job_active(job) }} tooltip bottom" data-text="{{ macros.job_state(job) }}" style="--dot-size: 1em;"> </div> <div class="dot {{ macros.job_state(job) }} {{ macros.job_active(job) }} tooltip bottom" data-text="{{ macros.job_state(job) }}" style="--dot-size: 1em;"> </div>

View file

@ -89,10 +89,12 @@ def poll_printers(app: App, db: Db) -> None:
) )
if "error" in status: 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 return False
similarity = status.get("similarity", 0.0) ** 3 # Cube it similarity = status.get("similarity", 0.0) ** 3 # Cube it
return similarity > 0.9 return similarity > 0.9
printer_job = {} printer_job = {}
@ -216,6 +218,21 @@ def push_jobs(app: App, db: Db) -> None:
else: else:
raise 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.select(Path(file.path).name)
client.start() client.start()
db.start_job(jid=job.id) 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") log.info(f"Job {job.id} has succeeded")
db.finish_job(jid=job.id, state="success") 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"): elif printer_state.get("error"):
log.warn(f"Job {job.id} has failed") log.warn(f"Job {job.id} has failed")
db.finish_job(jid=job.id, state="failed") db.finish_job(jid=job.id, state="failed")