From 373ff6b6c182387779a17ded4fa0ea7fe98dda01 Mon Sep 17 00:00:00 2001 From: Peter Siegmund Date: Thu, 15 Jan 2026 22:51:39 +0100 Subject: [PATCH] initial commit Signed-off-by: Peter Siegmund --- .dockerignore | 1 + .gitea/workflows/deploy.yml | 38 ++++++++++++++++ .gitignore | 2 + Dockerfile | 11 +++++ bambu.py | 90 +++++++++++++++++++++++++++++++++++++ 5 files changed, 142 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitea/workflows/deploy.yml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 bambu.py diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.env diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..df0e268 --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,38 @@ +name: Deploy Docker Image + +on: + workflow_dispatch: + push: + branches: + - main + +jobs: + build-and-push: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Set Registry Domain + run: | + REGISTRY_DOMAIN=$(echo "${{ github.server_url }}" | sed 's|https://||' | sed 's|http://||') + echo "REGISTRY_DOMAIN=$REGISTRY_DOMAIN" >> $GITHUB_ENV + + - name: Login to Gitea Registry + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY_DOMAIN }} + username: ${{ secrets.REGISTRY_USER }} + password: ${{ secrets.REGISTRY_PASSWORD }} + + - name: Build and push Docker image (multi-arch) + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + push: true + platforms: linux/amd64,linux/arm64 + tags: ${{ secrets.DOCKER_REGISTRY }}/${{ secrets.DOCKER_IMAGE_NAME }}:latest diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..055b8c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.venv/ +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b1b9b3e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +# Dockerfile für bambu.py +FROM python:3.11-slim + +WORKDIR /app + +COPY bambu.py /app/bambu.py + +# Optional: requirements.txt falls weitere Pakete benötigt werden +RUN pip install --no-cache-dir paho-mqtt dotenv + +CMD ["python", "-u", "bambu.py"] diff --git a/bambu.py b/bambu.py new file mode 100644 index 0000000..56fc572 --- /dev/null +++ b/bambu.py @@ -0,0 +1,90 @@ +# video url +# ffplay -rtsp_transport tcp -tls_verify 0 "rtsps://bblp:@:322/streaming/live/1" + +import ssl +import paho.mqtt.client as mqtt +import os +from dotenv import load_dotenv + +load_dotenv() + +# --- KONFIGURATION aus .env --- +PRINTER_IP = os.getenv("PRINTER_IP") +PRINTER_ACCESS_CODE = os.getenv("PRINTER_ACCESS_CODE") +PRINTER_SERIAL = os.getenv("PRINTER_SERIAL") + +TARGET_BROKER_IP = os.getenv("TARGET_BROKER_IP") +TARGET_PORT = int(os.getenv("TARGET_PORT", 8883)) +TARGET_USERNAME = os.getenv("TARGET_USERNAME") +TARGET_PASSWORD = os.getenv("TARGET_PASSWORD") +TARGET_PREFIX = os.getenv("TARGET_PREFIX", "bambulab/") + +# --- ZIEL-CLIENT (SINK) --- +def setup_target(): + client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2) + # TLS-Konfiguration für Ziel-Broker (Zertifikate werden geprüft) + client.tls_set(cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1_2) + # Authentifizierung + client.username_pw_set(TARGET_USERNAME, TARGET_PASSWORD) + try: + client.connect(TARGET_BROKER_IP, TARGET_PORT, 60) + client.loop_start() # Läuft im Hintergrund-Thread + print(f"[Target] Verbunden mit {TARGET_BROKER_IP}") + return client + except Exception as e: + print(f"[Target] Fehler: {e}") + exit(1) + +target_client = setup_target() + +# --- QUELL-CLIENT (SOURCE - BAMBULAB) --- +def on_connect_source(client, userdata, flags, rc, properties=None): + if rc == 0: + # Abonniere Haupt-Report Topic + topic = f"device/{PRINTER_SERIAL}/report" + client.subscribe(topic) + else: + print(f"[Source] Verbindung fehlgeschlagen. Code: {rc}") + +def on_message_source(client, userdata, msg): + import datetime + # Füge Prefix hinzu, z.B. bambu/device/SERIAL/report + mirror_topic = f"{TARGET_PREFIX}{msg.topic}" + # Prüfe, ob sich die Daten geändert haben + if not hasattr(on_message_source, "last_payloads"): + on_message_source.last_payloads = {} + last_payload = on_message_source.last_payloads.get(mirror_topic) + if last_payload != msg.payload: + target_client.publish(mirror_topic, msg.payload, qos=0, retain=False) + on_message_source.last_payloads[mirror_topic] = msg.payload + now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + print(f"[{now}] Empfangen & weitergeleitet: Topic={mirror_topic}, Bytes={len(msg.payload)}") + else: + now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + print(f"[{now}] Empfangen, aber nicht weitergeleitet (keine Änderung): Topic={mirror_topic}") + +def main(): + # BambuLab benötigt SSL/TLS, akzeptiert aber oft nur unsichere Zertifikate + source_client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2) + + # TLS Konfiguration für Self-Signed Certs + source_client.tls_set(cert_reqs=ssl.CERT_NONE, tls_version=ssl.PROTOCOL_TLSv1_2) + source_client.tls_insecure_set(True) + + # Auth: User ist IMMER 'bblp', Passwort ist der Access Code + source_client.username_pw_set("bblp", PRINTER_ACCESS_CODE) + + source_client.on_connect = on_connect_source + source_client.on_message = on_message_source + + try: + # Port 8883 ist Standard für BambuLab MQTTS + source_client.connect(PRINTER_IP, 8883, 60) + source_client.loop_forever() # Blockiert hier und hält das Script am Leben + except KeyboardInterrupt: + print("\nBeende...") + target_client.loop_stop() + source_client.disconnect() + +if __name__ == "__main__": + main() \ No newline at end of file