update directory structure

This commit is contained in:
Torben Haack
2024-10-11 06:08:03 +02:00
parent 1365f7e106
commit 577f6c71f5
12 changed files with 0 additions and 0 deletions

View File

@ -0,0 +1 @@
PRINTER_IPS=192.168.0.10,192.168.0.11,192.168.0.12

View File

@ -0,0 +1,106 @@
# 🖨️ 3D-Drucker Status API 📊
Willkommen beim Blueprint der 3D-Drucker Status API! Diese API ermöglicht es Ihnen, den Status mehrerer über LAN verbundener 3D-Drucker zu überwachen und Druckaufträge an sie zu senden.
## 🌟 Funktionen
- 🔍 Abrufen des Status von 3D-Druckern, einschließlich ihres aktuellen Status, Fortschrittes und Temperatur.
- 📥 Senden von Druckaufträgen an verfügbare 3D-Drucker.
- 💾 Speichern und Aktualisieren des Status jedes Druckers in einer SQLite-Datenbank.
## 🛠Verwendete Technologien
- 🐍 Python
- 🌶️ Flask
- 🗄️ SQLite
- 🌐 HTTP-Anfragen
## 📋 Verordnungen
Bevor Sie die API starten, stellen Sie sicher, dass Sie folgendes haben:
- Python 3.x installiert
- Flask und python-dotenv-Bibliotheken installiert (`pip install flask python-dotenv`)
- Eine Liste von IP-Adressen der 3D-Drucker, die Sie überwachen möchten
## 🚀 Erste Schritte
1. Klonen Sie das Repository:
```
git clone https://git.i.mercedes-benz.com/TBA-Berlin-FI/MYP
```
2. Installieren Sie die erforderlichen Abhängigkeiten:
```
pip install -r requirements.txt
```
3. Erstellen Sie eine `.env`-Datei im Projektverzeichnis und geben Sie die IP-Adressen Ihrer 3D-Drucker an:
```
PRINTER_IPS=192.168.0.10,192.168.0.11,192.168.0.12
```
4. Starten Sie das Skript, um die SQLite-Datenbank zu erstellen:
```
python create_db.py
```
5. Starten Sie den API-Server:
```
python app.py
```
6. Die API ist unter `http://localhost:5000` erreichbar.
## 📡 API-Endpunkte
- `GET /printer_status`: Rufen Sie den Status aller 3D-Drucker ab.
- `POST /print_job`: Senden Sie einen Druckauftrag an einen bestimmten 3D-Drucker.
## 📝 API-Nutzung
### Druckerstatus abrufen
Senden Sie eine `GET`-Anfrage an `/printer_status`, um den Status aller 3D-Drucker abzurufen.
Antwort:
```json
[
{
"ip": "192.168.0.10",
"status": "frei",
"progress": 0,
"temperature": 25
},
{
"ip": "192.168.0.11",
"status": "besetzt",
"progress": 50,
"temperature": 180
},
...
]
```
### Druckauftrag senden
Senden Sie eine `POST`-Anfrage an `/print_job` mit der folgenden JSON-Last, um einen Druckauftrag an einen bestimmten 3D-Drucker zu senden:
```json
{
"printer_ip": "192.168.0.10",
"file_url": "http://example.com/print_file.gcode"
}
```
Antwort:
```json
{
"message": "Druckauftrag gestartet"
}
```
## 📄 Lizenz
- --> Noch nicht verfügbar

View File

@ -0,0 +1,25 @@
import sqlite3
from dotenv import load_dotenv
import os
load_dotenv()
printers = os.getenv('PRINTER_IPS').split(',')
def create_db():
conn = sqlite3.connect('printers.db')
c = conn.cursor()
# Tabelle 'printers' erstellen, falls sie nicht existiert
c.execute('''CREATE TABLE IF NOT EXISTS printers
(ip TEXT PRIMARY KEY, status TEXT)''')
# Drucker-IPs in die Tabelle einfügen, falls sie noch nicht vorhanden sind
for printer_ip in printers:
c.execute("INSERT OR IGNORE INTO printers (ip, status) VALUES (?, ?)", (printer_ip, "frei"))
conn.commit()
conn.close()
print("Datenbank 'printers.db' erfolgreich erstellt.")
if __name__ == '__main__':
create_db()

View File

@ -0,0 +1,3 @@
flask==2.1.0
requests==2.25.1
python-dotenv==0.20.0

View File

@ -0,0 +1,94 @@
from flask import Flask, jsonify, request
import requests
import sqlite3
from dotenv import load_dotenv
import os
load_dotenv()
printers = os.getenv('PRINTER_IPS').split(',')
app = Flask(__name__)
# SQLite-Datenbank initialisieren
def init_db():
conn = sqlite3.connect('printers.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS printers
(ip TEXT PRIMARY KEY, status TEXT)''')
for printer_ip in printers:
c.execute("INSERT OR IGNORE INTO printers (ip, status) VALUES (?, ?)", (printer_ip, "frei"))
conn.commit()
conn.close()
@app.route('/printer_status', methods=['GET'])
def get_printer_status():
printer_status = []
conn = sqlite3.connect('printers.db')
c = conn.cursor()
for printer_ip in printers:
c.execute("SELECT status FROM printers WHERE ip = ?", (printer_ip,))
status = c.fetchone()[0]
try:
response = requests.get(f"http://{printer_ip}/api/printer/status")
if response.status_code == 200:
status_data = response.json()
printer_status.append({
"ip": printer_ip,
"status": status,
"progress": status_data["progress"],
"temperature": status_data["temperature"]
})
else:
printer_status.append({
"ip": printer_ip,
"status": "Fehler bei der Abfrage",
"progress": None,
"temperature": None
})
except:
printer_status.append({
"ip": printer_ip,
"status": "Drucker nicht erreichbar",
"progress": None,
"temperature": None
})
conn.close()
return jsonify(printer_status)
@app.route('/print_job', methods=['POST'])
def submit_print_job():
print_job = request.json
printer_ip = print_job["printer_ip"]
file_url = print_job["file_url"]
conn = sqlite3.connect('printers.db')
c = conn.cursor()
c.execute("SELECT status FROM printers WHERE ip = ?", (printer_ip,))
status = c.fetchone()[0]
if status == "frei":
try:
response = requests.post(f"http://{printer_ip}/api/print_job", json={"file_url": file_url})
if response.status_code == 200:
c.execute("UPDATE printers SET status = 'besetzt' WHERE ip = ?", (printer_ip,))
conn.commit()
conn.close()
return jsonify({"message": "Druckauftrag gestartet"}), 200
else:
conn.close()
return jsonify({"message": "Fehler beim Starten des Druckauftrags"}), 500
except:
conn.close()
return jsonify({"message": "Drucker nicht erreichbar"}), 500
else:
conn.close()
return jsonify({"message": "Drucker ist nicht frei"}), 400
if __name__ == '__main__':
init_db()
app.run(host='0.0.0.0', port=5000)

View File

@ -0,0 +1,38 @@
# entwendet aus:
# https://github.com/ut-hnl-lab/ultimakerpy
# auch zum lesen:
# https://github.com/MartinBienz/SDPremote?tab=readme-ov-file
import time
from ultimakerpy import UMS3, JobState
def print_started(state):
if state == JobState.PRINTING:
time.sleep(6.0)
return True
return False
def layer_reached(pos, n):
if round(pos / 0.2) >= n: # set layer pitch: 0.2 mm
return True
return False
printer = UMS3(name='MyPrinterName')
targets = {
'job_state': printer.job_state,
'bed_pos': printer.bed.position,
}
printer.print_from_dialog() # select file to print
printer.peripherals.camera_streaming()
with printer.data_logger('output2.csv', targets) as dl:
timer = dl.get_timer()
# sleep until active leveling finishes
timer.wait_for_datalog('job_state', print_started)
for n in range(1, 101):
# sleep until the printing of specified layer to start
timer.wait_for_datalog('bed_pos', lambda v: layer_reached(v, n))
print('printing layer:', n)

View File

@ -0,0 +1,148 @@
from flask import Flask, render_template, request, redirect, url_for, jsonify, session
import sqlite3
import bcrypt
app = Flask(__name__)
app.secret_key = 'supersecretkey'
# Database setup
def init_db():
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, username TEXT, password TEXT)''')
c.execute('''CREATE TABLE IF NOT EXISTS printers (id INTEGER PRIMARY KEY, name TEXT, status TEXT)''')
c.execute('''CREATE TABLE IF NOT EXISTS jobs (id INTEGER PRIMARY KEY, printer_id INTEGER, user TEXT, date TEXT, status TEXT)''')
conn.commit()
conn.close()
init_db()
# User registration (Admin setup)
def add_admin():
conn = sqlite3.connect('database.db')
c = conn.cursor()
hashed_pw = bcrypt.hashpw('adminpassword'.encode('utf-8'), bcrypt.gensalt())
c.execute("INSERT INTO users (username, password) VALUES (?, ?)", ('admin', hashed_pw))
conn.commit()
conn.close()
# Comment the next line after the first run
# add_admin()
# API Endpoints
@app.route('/api/printers/status', methods=['GET'])
def get_printer_status():
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute("SELECT * FROM printers")
printers = c.fetchall()
conn.close()
return jsonify(printers)
@app.route('/api/printers/job', methods=['POST'])
def create_job():
if not session.get('logged_in'):
return jsonify({'error': 'Unauthorized'}), 403
data = request.json
user = session['username']
printer_id = data['printer_id']
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute("SELECT status FROM printers WHERE id=?", (printer_id,))
status = c.fetchone()[0]
if status == 'frei':
c.execute("INSERT INTO jobs (printer_id, user, date, status) VALUES (?, ?, datetime('now'), 'in progress')",
(printer_id, user))
c.execute("UPDATE printers SET status='belegt' WHERE id=?", (printer_id,))
conn.commit()
elif status == 'belegt':
return jsonify({'error': 'Printer already in use'}), 409
else:
return jsonify({'error': 'Invalid printer status'}), 400
conn.close()
return jsonify({'message': 'Job created and printer turned on'}), 200
@app.route('/api/printers/reserve', methods=['POST'])
def reserve_printer():
if not session.get('logged_in'):
return jsonify({'error': 'Unauthorized'}), 403
data = request.json
printer_id = data['printer_id']
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute("SELECT status FROM printers WHERE id=?", (printer_id,))
status = c.fetchone()[0]
if status == 'frei':
c.execute("UPDATE printers SET status='reserviert' WHERE id=?", (printer_id,))
conn.commit()
message = 'Printer reserved'
else:
message = 'Printer cannot be reserved'
conn.close()
return jsonify({'message': message}), 200
@app.route('/api/printers/release', methods=['POST'])
def release_printer():
if not session.get('logged_in'):
return jsonify({'error': 'Unauthorized'}), 403
data = request.json
printer_id = data['printer_id']
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute("UPDATE printers SET status='frei' WHERE id=?", (printer_id,))
conn.commit()
conn.close()
return jsonify({'message': 'Printer released'}), 200
# Authentication routes
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password'].encode('utf-8')
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute("SELECT * FROM users WHERE username=?", (username,))
user = c.fetchone()
conn.close()
if user and bcrypt.checkpw(password, user[2].encode('utf-8')):
session['logged_in'] = True
session['username'] = username
return redirect(url_for('dashboard'))
else:
return render_template('login.html', error='Invalid Credentials')
return render_template('login.html')
@app.route('/dashboard')
def dashboard():
if not session.get('logged_in'):
return redirect(url_for('login'))
conn = sqlite3.connect('database.db')
c = conn.cursor()
c.execute("SELECT * FROM printers")
printers = c.fetchall()
conn.close()
return render_template('dashboard.html', printers=printers)
@app.route('/logout')
def logout():
session.clear()
return redirect(url_for('login'))
if __name__ == '__main__':
app.run(debug=True)

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Printer Management</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/daisyui@1.14.0/dist/full.css" rel="stylesheet">
</head>
<body class="bg-black text-white">
<nav class="bg-gray-800 p-4">
<div class="container mx-auto">
<h1 class="text-xl">3D Printer Management Dashboard</h1>
</div>
</nav>
<div class="container mx-auto mt-5">
{% block content %}{% endblock %}
</div>
</body>
</html>

View File

@ -0,0 +1,29 @@
{% extends "base.html" %}
{% block content %}
<h2 class="text-2xl mb-4">Printer Status</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{% for printer in printers %}
<div class="card bg-gray-900 shadow-xl">
<div class="card-body">
<h2 class="card-title">{{ printer[1] }}</h2>
<p>Status: {{ printer[2] }}</p>
{% if printer[2] == 'frei' %}
<form method="POST" action="/api/printers/job">
<input type="hidden" name="printer_id" value="{{ printer[0] }}">
<button class="btn btn-success mt-4 w-full">Start Job</button>
</form>
{% elif printer[2] == 'belegt' %}
<button class="btn btn-warning mt-4 w-full" disabled>In Use</button>
{% elif printer[2] == 'reserviert' %}
<form method="POST" action="/api/printers/release">
<input type="hidden" name="printer_id" value="{{ printer[0] }}">
<button class="btn btn-info mt-4 w-full">Release</button>
</form>
{% endif %}
</div>
</div>
{% endfor %}
</div>
<a href="/logout" class="btn btn-secondary mt-4">Logout</a>
{% endblock %}

View File

@ -0,0 +1,33 @@
{% extends "base.html" %}
{% block content %}
<div class="flex justify-center items-center h-screen">
<div class="card w-96 bg-gray-900 shadow-xl">
<div class="card-body">
<h2 class="card-title">Login</h2>
<form method="POST">
<div class="form-control">
<label class="label">
<span class="label-text">Username</span>
</label>
<input type="text" name="username" class="input input-bordered w-full" required>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Password</span>
</label>
<input type="password" name="password" class="input input-bordered w-full" required>
</div>
<div class="form-control mt-6">
<button class="btn btn-primary w-full">Login</button>
</div>
</form>
{% if error %}
<div class="mt-4 text-red-500">
{{ error }}
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}