The MES Printing Server provides GUI for Monash engineering students to submit and monitor 3D model printing jobs. Printing jobs are executed by calling Octo APIs to 3D printers in the lab, and real time printing data is synchronized to the OPCUA server, which is the central control of the lab.
MES works with other systems (matrix, storage...) to provide automated printing services:
- students submit printing jobs
- jobs are picked and executed
- finished plates are picked by robots to storage
- students get notified and come to the lab
- models are picked from storage to students
The printing server runs several printer workers. Each worker maintains a connection to one octoprint server and call octoprint APIs when needed. Responses of APIs are pushed to the OPCUA server.
sudo docker build -t mes-printing-server .
sudo docker run --rm --name mes-printing-server \
-v ./upload:/var/lib/mes/gcode-files \
-e UPLOAD_PATH="/var/lib/mes/gcode-files" \
mes-printing-server
We use poetry to manage dependencies. Please first install poetry.
Then, use poetry to install dependencies:
poetry install
Next, create an .env
file to store configuration.
We'll use an in-memory DB and a simulated OPC UA server,
so you don't need to set up other services for now.
cat << EOF > .env
DATABASE_URL='sqlite+aiosqlite:https://'
OPCUA_SERVER_URL='opc.tcp:https://mock-server:4840'
UPLOAD_PATH='./upload'
EOF
Finally, run the printing server in the virtual environment:
poetry shell
poetry run server
The API docs are available at https://localhost:8000/api/v1/docs
Configuration can be parsed from environment variables or a .env
file.
You can generate a .env
file for local development by running the shell command below.
An example env file is also available.
cat << EOF > .env
DATABASE_URL='sqlite+aiosqlite:https://'
OPCUA_SERVER_URL='opc.tcp:https://mock-server:4840'
UPLOAD_PATH='./upload'
EOF
Or setup environment variables directly
EXPORT DATABASE_URL='sqlite+aiosqlite:https://'
EXPORT OPCUA_SERVER_URL='opc.tcp:https://127.0.0.1:4840'
EXPORT UPLOAD_PATH='./upload'
poetry run setting
DATABASE_URL
: URL of the databaseOPCUA_SERVER_URL
: URL of the OPCUA serverUPLOAD_PATH
: path to store uploadedGCode
files
AUTO_SCHEDULE
: if set totrue
, the schedule will assign pending jobs to ready printersPRINTER_WORKER_INTERVAL
: if set tox
, all printer workers will run everyx
secondsORDER_FETCHER_INTERVAL
: if set tox
, the printer server will fetch pending orders everyx
secondsMOCK_PRINTER_INTERVAL
: if set tox
, all mock printers will update inner states everyx
secondsMOCK_PRINTER_JOB_TIME
: mock printers will takeMOCK_PRINTER_INTERVAL
*MOCK_PRINTER_JOB_TIME
seconds to print all printing jobsMOCK_PRINTER_TARGET_BED_TEMPERATURE
: target bed temperature of the mock printerMOCK_PRINTER_TARGET_BED_NOZZLE
: target nozzle temperature of the mock printer
If the OPC UA Server url contains mock
(for example opc.tcp:https://mock-server:4840
), the server will use a mock OPC UA
server.
If api
of a printer is Mock
, the server will use a mock printer instead of calling REST APIs on a real printer.
curl --location 'https://localhost:8000/api/v1/printers' \
--header 'Content-Type: application/json' \
--data '{
"url": "https://mock-printer1:5000",
"api": "Mock",
"api_key": "FJZ3PO9",
"opcua_name": "Printer1",
"worker": true
}'
You can specify sqlite+aiosqlite:https:///
as the database URL to tell the server to set up an in memory SQLite database.
poetry run pytest tests/
A printer worker periodically fetches current status of a printer and acts call printer APIs to control printing jobs. Printer worker monitors states of all printing jobs (submitted through both server and printer), but only controls jobs (print/cancel) submitted though server.
As the diagram shown below, the printer worker queries the previous job status from database, and fetch current job status from the printer. By comparing previous and current status, the printer worker knows what happened between these states and react according to the state change.
Printer worker is stateless, which means it doesn't maintain any internal states. This prevents data loss if the printing server is down when tracking a printing job, and simplifies testing.
---
title: Printer Server ERD
---
erDiagram
User ||--o{ Order: has
Order o|--o| Job: contains
Job o|--|| Printer: "is printed by"
Job ||--o{ JobHistory: "records"
User {
string id PK "Auth0 subject"
string email
string name
string permission "admin/user"
datetime create_time
}
Printer {
int id PK
string group_name
int url
string api_key
string camera_url
string api "OctoPrint/Prusa/Mock"
bool has_worker "run printer worker?"
string opcua_name
string model "e.g. Prusa XL"
datetime create_time
}
Job {
int id PK
int printer_id FK
int order_id FK
int user_id FK
int status "bitmask"
bool from_server "submitted through server?"
string gcode_file_path
string printer_filename
string original_filename
}
JobHistory {
int id PK
int job_id FK
string status "e.g. approved"
datetime create_time
}
Order {
int id PK
string user_id FK
datetime create_time
}