added bluetooth connect and test-hub script
This commit is contained in:
parent
6f30454fb9
commit
d3ba2c270d
143
app.py
143
app.py
@ -4,9 +4,13 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
from flask import Flask, render_template, redirect, url_for, send_from_directory, request, jsonify
|
from flask import Flask, render_template, redirect, url_for, send_from_directory, request, jsonify
|
||||||
|
|
||||||
|
# ── Bluetooth ────────────────────────────────────────────────────────────────
|
||||||
|
from mkconnect.mouldking.MouldKing import MouldKing
|
||||||
|
from mkconnect.tracer.TracerConsole import TracerConsole
|
||||||
|
from mkconnect.advertiser.AdvertiserBTSocket import AdvertiserBTSocket
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
# Konfiguration
|
|
||||||
app.config['CONFIG_DIR'] = 'configs'
|
app.config['CONFIG_DIR'] = 'configs'
|
||||||
os.makedirs(app.config['CONFIG_DIR'], exist_ok=True)
|
os.makedirs(app.config['CONFIG_DIR'], exist_ok=True)
|
||||||
|
|
||||||
@ -17,15 +21,18 @@ logging.basicConfig(
|
|||||||
format='%(asctime)s | %(levelname)-8s | %(message)s',
|
format='%(asctime)s | %(levelname)-8s | %(message)s',
|
||||||
datefmt='%Y-%m-%d %H:%M:%S'
|
datefmt='%Y-%m-%d %H:%M:%S'
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Bluetooth-Komponenten (einmalig initialisieren)
|
||||||
|
tracer = TracerConsole()
|
||||||
|
advertiser = AdvertiserBTSocket() # ← ohne tracer, wie korrigiert
|
||||||
|
|
||||||
|
# Globale Zustände (für Einzelbenutzer / Entwicklung – später Session/DB)
|
||||||
|
current_config = None
|
||||||
|
current_hub: MouldKing | None = None
|
||||||
|
|
||||||
def load_configs():
|
def load_configs():
|
||||||
"""Liest alle .json Dateien aus dem configs-Ordner"""
|
|
||||||
configs = []
|
configs = []
|
||||||
if not os.path.exists(app.config['CONFIG_DIR']):
|
|
||||||
return configs
|
|
||||||
|
|
||||||
for filename in os.listdir(app.config['CONFIG_DIR']):
|
for filename in os.listdir(app.config['CONFIG_DIR']):
|
||||||
if filename.lower().endswith('.json'):
|
if filename.lower().endswith('.json'):
|
||||||
path = os.path.join(app.config['CONFIG_DIR'], filename)
|
path = os.path.join(app.config['CONFIG_DIR'], filename)
|
||||||
@ -33,91 +40,129 @@ def load_configs():
|
|||||||
with open(path, 'r', encoding='utf-8') as f:
|
with open(path, 'r', encoding='utf-8') as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
data['filename'] = filename
|
data['filename'] = filename
|
||||||
# Optional: name fallback, falls nicht vorhanden
|
|
||||||
data.setdefault('name', filename.replace('.json', '').replace('_', ' ').title())
|
data.setdefault('name', filename.replace('.json', '').replace('_', ' ').title())
|
||||||
configs.append(data)
|
configs.append(data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Fehler beim Laden von {filename}: {e}")
|
logger.error(f"Fehler beim Laden {filename}: {e}")
|
||||||
return sorted(configs, key=lambda x: x.get('name', ''))
|
return sorted(configs, key=lambda x: x.get('name', ''))
|
||||||
|
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
configs = load_configs()
|
return render_template('index.html', configs=load_configs())
|
||||||
return render_template('index.html', configs=configs)
|
|
||||||
|
|
||||||
@app.route('/configs/<path:filename>')
|
|
||||||
def serve_config_file(filename):
|
|
||||||
"""Liefert Bilder und Dateien aus dem configs-Ordner aus"""
|
|
||||||
try:
|
|
||||||
return send_from_directory(app.config['CONFIG_DIR'], filename)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Fehler beim Ausliefern von {filename}: {e}")
|
|
||||||
return "Datei nicht gefunden", 404
|
|
||||||
|
|
||||||
current_config = None
|
|
||||||
current_filename = None
|
|
||||||
|
|
||||||
@app.route('/load_config/<filename>')
|
@app.route('/load_config/<filename>')
|
||||||
def load_config(filename):
|
def load_config(filename):
|
||||||
global current_config, current_filename
|
global current_config
|
||||||
path = os.path.join(app.config['CONFIG_DIR'], filename)
|
path = os.path.join(app.config['CONFIG_DIR'], filename)
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
return "Konfigurationsdatei nicht gefunden", 404
|
return "Datei nicht gefunden", 404
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(path, 'r', encoding='utf-8') as f:
|
with open(path, 'r', encoding='utf-8') as f:
|
||||||
current_config = json.load(f)
|
current_config = json.load(f)
|
||||||
current_config['filename'] = filename
|
current_config['filename'] = filename
|
||||||
current_filename = filename
|
logger.info(f"Config geladen: {filename}")
|
||||||
logger.info(f"Konfiguration geladen: {filename}")
|
|
||||||
return redirect(url_for('control_page'))
|
return redirect(url_for('control_page'))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Fehler beim Laden der Config {filename}: {e}")
|
logger.error(f"Config-Ladefehler {filename}: {e}")
|
||||||
return "Fehler beim Laden der Konfiguration", 500
|
return "Fehler beim Laden", 500
|
||||||
|
|
||||||
|
|
||||||
@app.route('/control')
|
@app.route('/control')
|
||||||
def control_page():
|
def control_page():
|
||||||
if current_config is None:
|
if current_config is None:
|
||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
return render_template('control.html', config=current_config)
|
return render_template('control.html', config=current_config)
|
||||||
|
|
||||||
|
|
||||||
# Neue API-Route (Platzhalter – später echte Bluetooth-Steuerung)
|
@app.route('/configs/<path:filename>')
|
||||||
|
def serve_config_file(filename):
|
||||||
|
return send_from_directory(app.config['CONFIG_DIR'], filename)
|
||||||
|
|
||||||
|
|
||||||
|
# ── API ──────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@app.route('/api/connect', methods=['POST'])
|
@app.route('/api/connect', methods=['POST'])
|
||||||
def api_connect():
|
def api_connect():
|
||||||
# Hier kommt später der echte Code mit MouldKing
|
global current_hub
|
||||||
# Aktuell nur simuliert
|
|
||||||
if current_config is None:
|
if current_config is None:
|
||||||
return jsonify({"success": False, "message": "Keine Konfiguration geladen"}), 400
|
return jsonify({"success": False, "message": "Keine Konfiguration geladen"}), 400
|
||||||
|
|
||||||
logger.info(f"Simulierter Connect zu Hub {current_config.get('hub_id')}")
|
try:
|
||||||
return jsonify({
|
hub_id = int(current_config.get('hub_id', 0))
|
||||||
"success": True,
|
|
||||||
"message": "Verbunden (Simulation)",
|
# Falls schon verbunden → erstmal trennen (sauberer Neustart)
|
||||||
"hub_id": current_config.get('hub_id')
|
if current_hub is not None:
|
||||||
})
|
try:
|
||||||
|
current_hub.disconnect() # oder .close() – je nach Methode
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
current_hub = MouldKing(
|
||||||
|
hub_id=hub_id,
|
||||||
|
advertiser=advertiser,
|
||||||
|
tracer=tracer # ← falls das doch geht; sonst entfernen
|
||||||
|
)
|
||||||
|
|
||||||
|
current_hub.connect() # ← das ist der entscheidende Aufruf
|
||||||
|
logger.info(f"Erfolgreich verbunden mit Hub-ID {hub_id}")
|
||||||
|
return jsonify({"success": True, "message": f"Hub {hub_id} verbunden"})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception("Connect-Fehler")
|
||||||
|
return jsonify({
|
||||||
|
"success": False,
|
||||||
|
"message": f"Verbindungsfehler: {str(e)}"
|
||||||
|
}), 500
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/control', methods=['POST'])
|
@app.route('/api/control', methods=['POST'])
|
||||||
def api_control():
|
def api_control():
|
||||||
# Platzhalter für spätere echte Steuerung
|
global current_hub
|
||||||
data = request.get_json()
|
if current_hub is None:
|
||||||
logger.info(f"Steuerbefehl empfangen: {data}")
|
return jsonify({"success": False, "message": "Nicht verbunden"}), 400
|
||||||
return jsonify({"success": True, "message": "Befehl gesendet (Simulation)"})
|
|
||||||
|
try:
|
||||||
|
data = request.get_json()
|
||||||
|
port = data['port']
|
||||||
|
value = float(data['value'])
|
||||||
|
|
||||||
|
# Config-spezifische Anpassungen
|
||||||
|
channel_config = next((c for c in current_config['channels'] if c['port'] == port), None)
|
||||||
|
if channel_config:
|
||||||
|
if channel_config.get('invert', False):
|
||||||
|
value = -value
|
||||||
|
if channel_config.get('negative_only', False) and value >= 0:
|
||||||
|
value = -abs(value)
|
||||||
|
if channel_config['type'] != 'motor':
|
||||||
|
value = channel_config.get('on_value', 1.0) if value != 0 else channel_config.get('off_value', 0.0)
|
||||||
|
|
||||||
|
# Hier kommt der echte Aufruf
|
||||||
|
current_hub.set_motor(channel=port, power=value) # ← ← ← Kernaufruf
|
||||||
|
|
||||||
|
logger.info(f"Steuerung: {port} → {value:.2f}")
|
||||||
|
return jsonify({"success": True})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception("Control-Fehler")
|
||||||
|
return jsonify({"success": False, "message": str(e)}), 500
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/stop_all', methods=['POST'])
|
@app.route('/api/stop_all', methods=['POST'])
|
||||||
def api_stop_all():
|
def api_stop_all():
|
||||||
logger.info("Alle stoppen (Simulation)")
|
global current_hub
|
||||||
return jsonify({"success": True, "message": "Alle Kanäle gestoppt"})
|
if current_hub is None:
|
||||||
|
return jsonify({"success": False, "message": "Nicht verbunden"}), 400
|
||||||
|
|
||||||
@app.route('/admin')
|
try:
|
||||||
def admin():
|
current_hub.stop_all() # ← oder alle Kanäle manuell auf 0 setzen
|
||||||
return render_template('admin.html')
|
logger.info("Alle Kanäle gestoppt")
|
||||||
|
return jsonify({"success": True})
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception("Stop-Fehler")
|
||||||
|
return jsonify({"success": False, "message": str(e)}), 500
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(host='0.0.0.0', port=5055, debug=True)
|
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||||
9
other/test-hub.py
Normal file
9
other/test-hub.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# test_hub.py
|
||||||
|
from mkconnect.mouldking.MouldKing import MouldKing
|
||||||
|
from mkconnect.tracer.TracerConsole import TracerConsole
|
||||||
|
from mkconnect.advertiser.AdvertiserBTSocket import AdvertiserBTSocket
|
||||||
|
|
||||||
|
tracer = TracerConsole()
|
||||||
|
adv = AdvertiserBTSocket()
|
||||||
|
hub = MouldKing(hub_id=0, advertiser=adv, tracer=tracer)
|
||||||
|
print(dir(hub)) # ← zeigt alle Methoden
|
||||||
Loading…
x
Reference in New Issue
Block a user