Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. IOBroker Automatisiertes Deployment

    NEWS

    • Amazon Alexa - ioBroker Skill läuft aus ?

    • Monatsrückblick – September 2025

    • Neues Video "KI im Smart Home" - ioBroker plus n8n

    IOBroker Automatisiertes Deployment

    This topic has been deleted. Only users with topic management privileges can see it.
    • V
      Vippis last edited by Vippis

      Hallo Community,

      ich bin dabei ein Deployment Skript für IOBroker zu erstellen, um automatisiert Raspberry Pis aufzusetzen mit einem immer gleichen Basissystem.

      Docker compose läuft. Ich brauche Hilfe bei folgenden Deployment per IOB CLI:

      • IOB Admin Passwort automatisiert setzen

      • Welcome Screen überspringen

      • Land/Stadt in Systemeinstellungen setzen (für Javascript astro)

      • Javascript+MQTT-Client Adapter installieren

      • MQTT-Client Instanz mit Username/PW/Host vom MQTT Broker konfigurieren

      • Bestimmte NPM Pakete für Javascript installieren

      • Javascripte aus Backup importieren (aus Dropbox)

      • 0.userdata Baum aus Backup importieren (aus Dropbox)

      • Bestimmte Datenpunkte in 0.userdata mit Infos befüllen, damit die Skripte zum Beispiel InfluxDB Credentials kennen

      Habe zu den meisten Punkten von ChatGPT gefragt, aber der stößt an seine Grenzen.

      Bedanke mich recht herzlich für Eure Hilfe!

      Marc Berg OliverIO 2 Replies Last reply Reply Quote 0
      • Marc Berg
        Marc Berg Most Active @Vippis last edited by

        @vippis sagte in IOBroker Automatisiertes Deployment:

        Habe zu den meisten Punkten von ChatGPT gefragt, aber der stößt an seine Grenzen.

        Bedanke mich recht herzlich für Eure Hilfe!

        Einen Teil der Anforderungen habe ich mit einem userscript umgesetzt, welches beim ersten Start des Containers automatisch ausgeführt wird. Dazu wird z.B. ein Scriptverzeichnis in den Container gemappt

            volumes:
              - /opt/docker/iobroker2:/opt/iobroker
              - /opt/docker/userscripts/test:/opt/userscripts
        

        Das Script muss "userscript_firststart.sh" heißen. Mein Script sieht dann so aus (weil es ein testsytem ist, Sentry abgeschaltet). Das lässt sich sicher noch um einige deiner Punkte ergänzen

        #!/bin/bash
        
        # To run the Script on the first start of a new container you have to rename it to userscript_firststart.sh.
        echo " "
        echo "Checking if Discovery Adapter is installed..."
        
        # Check if the Discovery Adapter is installed
        if iob list adapters | grep -q "discovery"; then
            echo "Deleting Discovery Adapter ..."
            iob del discovery
        else
            echo "Discovery Adapter is not installed."
        fi
        
        echo " "
        
        # Define variables for system.config parameters
        LICENSE_CONFIRMED=true
        SITE_NAME="TEST  +++++++  TEST  +++++++  TEST  +++++++  TEST"
        DIAG="none"
        REPO="beta"
        LANGUAGE="en"
        CITY="Test"
        COUNTRY="Germany"
        LONGITUDE="10.0000"
        LATITUDE="52.0000"
        
        echo "Confirm license ..."
        current_license=$(iob object get system.config | jq -r '.common.licenseConfirmed')
        if [ "$current_license" != "$LICENSE_CONFIRMED" ]; then
            iob object set system.config common.licenseConfirmed=$LICENSE_CONFIRMED
        fi
        
        echo "Setting Site Name ..."
        current_siteName=$(iob object get system.config | jq -r '.common.siteName')
        if [ "$current_siteName" != "$SITE_NAME" ]; then
            iob object set system.config common.siteName="$SITE_NAME"
        fi
        
        echo "Setting Diag Data ..."
        current_diag=$(iob object get system.config | jq -r '.common.diag')
        if [ "$current_diag" != "$DIAG" ]; then
            iob object set system.config common.diag="$DIAG"
        fi
        
        echo "Setting Repo ..."
        current_repo=$(iob object get system.config | jq -r '.common.activeRepo')
        if [ "$current_repo" != "$REPO" ]; then
            iob object set system.config common.activeRepo="$REPO"
        fi
        
        echo "Setting Language ..."
        current_language=$(iob object get system.config | jq -r '.common.language')
        if [ "$current_language" != "$LANGUAGE" ]; then
            iob object set system.config common.language="$LANGUAGE"
        fi
        
        echo "Setting miscellaneous ..."
        current_city=$(iob object get system.config | jq -r '.common.city')
        if [ "$current_city" != "$CITY" ]; then
            iob object set system.config common.city="$CITY"
        fi
        
        current_country=$(iob object get system.config | jq -r '.common.country')
        if [ "$current_country" != "$COUNTRY" ]; then
            iob object set system.config common.country="$COUNTRY"
        fi
        
        current_longitude=$(iob object get system.config | jq -r '.common.longitude')
        if [ "$current_longitude" != "$LONGITUDE" ]; then
            iob object set system.config common.longitude="$LONGITUDE"
        fi
        
        current_latitude=$(iob object get system.config | jq -r '.common.latitude')
        if [ "$current_latitude" != "$LATITUDE" ]; then
            iob object set system.config common.latitude="$LATITUDE"
        fi
        
        echo " "
        echo "Disable Sentry ..."
        iob plugin disable sentry
        echo " "
        
        exit 0
        
        1 Reply Last reply Reply Quote 0
        • OliverIO
          OliverIO @Vippis last edited by

          @vippis

          ein paar der punkte kannst du aus dem dev-server nehmen
          https://github.com/ioBroker/dev-server/blob/93790110fa07cf60da42bfd97cbf51c6dc75b6f9/src/index.ts#L1352

          da wird für die entwicklung eine iobroker instanz erstellt mit bestimmten voreinstellungen.
          vieles findest du im datenpunkt
          system.config

          V 1 Reply Last reply Reply Quote 0
          • V
            Vippis @OliverIO last edited by

            Vielen Dank schonmal @OliverIO und @Marc-Berg

            Die härteste Nuss finde ich fast das Admin PW setzen.

            Im Fall von Docker kann man ja

            docker exec iobroker bash -lc "iobroker user passwd '${IOB_ADMIN_USER}' '${IOB_ADMIN_PASSWORD}'"

            ausführen, aber ich lande immer in einer User-Eingabe das Passwort zu setzen. Geht das nicht per Skript?

            Und die NPM Pakete für den JS Adapter. Habt ihr da auch ein Kommando?

            OliverIO Marc Berg 2 Replies Last reply Reply Quote 0
            • OliverIO
              OliverIO @Vippis last edited by

              @vippis

              wenn du solche dinge machen willst, wirst du dich mit den tieferen ebenen des iobrokers beschäftigen müssen
              https://github.com/ioBroker/ioBroker.js-controller/blob/68fdbe2f4c4f0bef8b50f5e3b534363ebe77a15d/packages/common-db/src/lib/common/password.ts

              keine ahnung ob das angegebene beispiel auch genau so funktioniert und gültige passwörter für die aktuelle instanz ausspuckt, die man dann schreiben kann

              1 Reply Last reply Reply Quote 0
              • Marc Berg
                Marc Berg Most Active @Vippis last edited by Marc Berg

                @vippis sagte in IOBroker Automatisiertes Deployment:

                docker exec iobroker bash -lc "iobroker user passwd '${IOB_ADMIN_USER}' '${IOB_ADMIN_PASSWORD}'"

                docker exec -it iobroker2 bash -c 'printf "dein_neues_passwort\ndein_neues_passwort\n" | iobroker user passwd admin'
                Enter your password:
                Repeat your password:
                Password for "admin" was successfully set.
                

                So kann man das Passwort automatisch setzen. (ohne Abfrage)

                V 1 Reply Last reply Reply Quote 0
                • V
                  Vippis @Marc Berg last edited by Vippis

                  Für die Installation der NPM Module:

                  #!/bin/bash
                  log() { echo -e "[INFO] $1"; }
                  
                  IOBROKER_CID="iobroker"
                  IOBROKER_NPM_PACKAGES=("moment" "axios" "influxdb-client" "@influxdata/influxdb-client" "@influxdata/influxdb-client-apis")
                  
                  # Array in Leerzeichen-getrennten String umwandeln
                  libs_string=$(printf "%s " "${IOBROKER_NPM_PACKAGES[@]}")
                  libs_string="${libs_string%" "}"   # letztes Leerzeichen entfernen
                  
                  log "➡️ Setze libraries für javascript.0 auf: ${libs_string}"
                  
                  docker exec -u 0 "${IOBROKER_CID}" bash -c \
                    "iobroker object extend system.adapter.javascript.0 '{\"native\":{\"libraries\":\"${libs_string}\"}}'"
                  
                  # Danach sicherstellen, dass die Instanz die Pakete kennt
                  docker exec -u 0 "${IOBROKER_CID}" bash -c "iobroker upload javascript"
                  docker exec -u 0 "${IOBROKER_CID}" bash -c "iobroker restart javascript.0 || true"
                  
                  
                  V 1 Reply Last reply Reply Quote 0
                  • V
                    Vippis @Vippis last edited by

                    Wie kann ich die erstellten Javascripts, die ich über die GUI aus einem Quellsystem exportiert habe mit der nativen Funktion, per CLI wieder importieren, so dass sie unter "Scripts" in der Admin GUI erscheinen?

                    Wie kann ich einen Usertree unter 0_userdata wieder per CLI importieren?

                    OliverIO 1 Reply Last reply Reply Quote 0
                    • OliverIO
                      OliverIO @Vippis last edited by OliverIO

                      @vippis

                      Da würde ich vorhandenes nutzen
                      Backitup

                      Oder dort nachschauen wie es dort gemacht wird

                      V 1 Reply Last reply Reply Quote 0
                      • V
                        Vippis @OliverIO last edited by Vippis

                        @oliverio

                        Ich wollte euch mal ein funktionierendes Skript posten, wie ihr voll automatisiert Skripte in IOBroker importieren könnt.

                        Das Skript geht davon aus, dass ihr eure Skripte vorher per Export aus der Skripte GUI exportiert habt (scripts.zip). Das Zip File hat also eine entsprechend vorgegebene Struktur.

                        Usage:
                        sudo ./script.sh <pfad/zur/zip>

                        #!/usr/bin/env bash
                        set -uo pipefail
                        
                        usage() {
                          cat <<'USAGE'
                        Usage:
                          import_iob_scripts_zip_docker.sh <scripts.zip> [--container iobroker] [--instance javascript.0] [--dry-run]
                        
                        Options:
                          --container   ioBroker container name (default: iobroker)
                          --instance    JavaScript adapter instance (default: javascript.0)
                          --dry-run     Print actions only (no changes)
                        USAGE
                        }
                        
                        [[ $# -ge 1 ]] || { usage; exit 1; }
                        ZIP="$1"; shift || true
                        CONTAINER="iobroker"
                        ENGINE_INSTANCE="javascript.0"
                        DRY_RUN=0
                        while [[ $# -gt 0 ]]; do
                          case "$1" in
                            --container) CONTAINER="${2:-iobroker}"; shift 2 ;;
                            --instance)  ENGINE_INSTANCE="${2:-javascript.0}"; shift 2 ;;
                            --dry-run)   DRY_RUN=1; shift ;;
                            -h|--help)   usage; exit 0 ;;
                            *) echo "Unknown option: $1" >&2; usage; exit 2 ;;
                          esac
                        done
                        
                        for bin in docker unzip jq iconv sed; do
                          command -v "$bin" >/dev/null 2>&1 || { echo "ERROR: missing $bin"; exit 3; }
                        done
                        [[ -f "$ZIP" ]] || { echo "ERROR: ZIP not found: $ZIP"; exit 4; }
                        docker ps --format '{{.Names}}' | grep -qx "$CONTAINER" || { echo "ERROR: container '$CONTAINER' not running"; exit 5; }
                        
                        # Ensure jq in container
                        if ! docker exec -i "$CONTAINER" sh -lc 'command -v jq >/dev/null'; then
                          echo "ERROR: jq fehlt im Container."
                          exit 6
                        fi
                        
                        iob(){ docker exec -i "$CONTAINER" iobroker "$@"; }
                        
                        TMPDIR="$(mktemp -d -t iob-scripts-zip-XXXXXX)"
                        trap 'rm -rf "$TMPDIR"' EXIT
                        
                        echo "==> Entpacke ZIP auf dem Host: $TMPDIR"
                        unzip -q "$ZIP" -d "$TMPDIR"
                        
                        CONTAINER_TMP="/tmp/iob-scripts-import"
                        docker exec -i "$CONTAINER" sh -lc "rm -rf '$CONTAINER_TMP' && mkdir -p '$CONTAINER_TMP'" >/dev/null
                        
                        echo "==> Stoppe Adapter: $ENGINE_INSTANCE"
                        [[ $DRY_RUN -eq 1 ]] || iob stop "$ENGINE_INSTANCE"
                        
                        # Sammle Ordner (_dir.json) und Skripte (*.json ohne _dir.json)
                        mapfile -d '' DIR_FILES    < <(find "$TMPDIR" -type f -name '_dir.json' -print0)
                        mapfile -d '' SCRIPT_FILES < <(find "$TMPDIR" -type f -name '*.json' -print0 | grep -z -v '_dir.json$')
                        
                        TOTAL=$(( ${#DIR_FILES[@]} + ${#SCRIPT_FILES[@]} ))
                        echo "==> Gefundene Objekte: $TOTAL (Ordner: ${#DIR_FILES[@]}, Skripte: ${#SCRIPT_FILES[@]})"
                        [[ $TOTAL -gt 0 ]] || { echo "Keine importierbaren Objekte gefunden."; exit 0; }
                        
                        # Fortschrittsanzeige
                        progress_file="$TMPDIR/progress.count"
                        : > "$progress_file"
                        
                        show_progress() {
                          local total=$1
                          local width=40
                          while true; do
                            local done
                            done=$(wc -l < "$progress_file")
                            [[ $done -gt $total ]] && done=$total
                            local filled=$(( done * width / total ))
                            local empty=$(( width - filled ))
                            printf "\r[%s%s] %d/%d" \
                              "$(printf '#%.0s' $(seq 1 $filled))" \
                              "$(printf ' %.0s' $(seq 1 $empty))" \
                              "$done" "$total"
                            [[ $done -ge $total ]] && break
                            sleep 0.2
                          done
                          echo
                        }
                        show_progress "$TOTAL" &
                        PROGRESS_PID=$!
                        
                        # Import Ordner aus _dir.json (type, common inkl. lokalisierter Namen, native)
                        import_dir() {
                          local dirjson="$1"
                          local obj_id folder_obj
                        
                          obj_id="$(jq -r '._id' "$dirjson")"
                          [[ -n "$obj_id" && "$obj_id" != "null" ]] || return
                        
                          # Übernehme type/common/native vollständig; system Felder (from, ts, acl) lässt ioBroker selbst setzen
                          folder_obj="$(jq -c '{type,common,native}' "$dirjson")"
                        
                          if [[ $DRY_RUN -eq 1 ]]; then
                            echo "[dry-run] Ordner: $obj_id"
                          else
                            docker exec -i "$CONTAINER" iobroker object set "$obj_id" "$folder_obj"
                          fi
                          echo 1 >> "$progress_file"
                        }
                        
                        # Import Skriptobjekt + Source
                        import_script() {
                          local scriptjson="$1"
                          local base rel orig_root root_mapped path obj_id script_key
                          base="$(basename "$scriptjson")"
                          rel="${scriptjson#"$TMPDIR/"}"
                          orig_root="${rel%%/*}"
                        
                          # Mappe lokalisierte Root-Namen
                          case "$orig_root" in
                            "Allgemeine Skripte (common)") root_mapped="common" ;;
                            "Globale Skripte (global)")    root_mapped="global" ;;
                            *)                              root_mapped="$orig_root" ;;
                          esac
                        
                          path="${rel#"$orig_root/"}"
                          path="${path%.json}"
                          path="${path//\//.}"
                          obj_id="script.js.$root_mapped.$path"
                          script_key="$(echo "$obj_id" | tr '/ ' '__')"
                        
                          local common_json_host source_txt_host
                          common_json_host="$TMPDIR/common_${script_key}.json"
                          source_txt_host="$TMPDIR/source_${script_key}.txt"
                        
                          if jq -er 'type=="object" and has("common") and .common|has("source")' "$scriptjson" >/dev/null 2>&1; then
                            local name engineType expert debug verbose enabled
                            name="$(jq -r '.common.name // empty' "$scriptjson")"
                            [[ -n "$name" && "$name" != "null" ]] || name="${base%.json}"
                            engineType="$(jq -r '.common.engineType // "Javascript/Node.js"' "$scriptjson")"
                            expert="$(jq -r '.common.expert // false' "$scriptjson")"
                            debug="$(jq -r  '.common.debug  // false' "$scriptjson")"
                            verbose="$(jq -r '.common.verbose // false' "$scriptjson")"
                            enabled="$(jq -r '.common.enabled // false' "$scriptjson")"
                        
                            jq -c -n --arg name "$name" \
                                     --arg engine "system.adapter.$ENGINE_INSTANCE" \
                                     --arg engineType "$engineType" \
                                     --argjson expert "$expert" \
                                     --argjson debug "$debug" \
                                     --argjson verbose "$verbose" \
                                     --argjson enabled "$enabled" '
                              { name:$name, engine:$engine, engineType:$engineType,
                                expert:$expert, debug:$debug, verbose:$verbose, enabled:$enabled }' > "$common_json_host"
                        
                            jq -r '.common.source' "$scriptjson" > "$source_txt_host"
                          else
                            # Reines Source-JSON: Header entfernen, Defaults setzen
                            sed -e '/\/\* -- do not edit following lines - START --/,/-- do not edit previous lines - END --\*\//d' "$scriptjson" > "$source_txt_host"
                            jq -c -n --arg name "${base%.json}" \
                                     --arg engine "system.adapter.$ENGINE_INSTANCE" \
                                     --arg engineType "Javascript/Node.js" '
                              { name:$name, engine:$engine, engineType:$engineType,
                                expert:false, debug:false, verbose:false, enabled:false }' > "$common_json_host"
                          fi
                        
                          # Encoding säubern
                          iconv -f UTF-8 -t UTF-8 -c "$source_txt_host" | tr -d '\000' > "$source_txt_host.clean"
                          mv "$source_txt_host.clean" "$source_txt_host"
                        
                          if [[ $DRY_RUN -eq 1 ]]; then
                            echo "[dry-run] Script: $obj_id"
                          else
                            # Objekt anlegen (idempotent)
                            docker exec -i "$CONTAINER" iobroker object set "$obj_id" '{"type":"script","common":{"name":""},"native":{}}' >/dev/null
                        
                            # common setzen
                            docker cp "$common_json_host" "$CONTAINER:$CONTAINER_TMP/common_${script_key}.json" >/dev/null
                            docker exec -i "$CONTAINER" sh -lc "C=\$(cat $CONTAINER_TMP/common_${script_key}.json); iobroker object set '$obj_id' \"common=\$C\"" >/dev/null
                        
                            # source setzen (als JSON-String)
                            docker cp "$source_txt_host" "$CONTAINER:$CONTAINER_TMP/source_${script_key}.txt" >/dev/null
                            docker exec -i "$CONTAINER" sh -lc "SRC_JSON=\$(jq -Rn --rawfile s '$CONTAINER_TMP/source_${script_key}.txt' '\$s'); iobroker object set '$obj_id' \"common.source=\$SRC_JSON\"" >/dev/null
                          fi
                        
                          echo 1 >> "$progress_file"
                        }
                        
                        export -f import_dir import_script show_progress
                        export TMPDIR CONTAINER CONTAINER_TMP ENGINE_INSTANCE progress_file
                        
                        echo "==> Importiere Ordner (_dir.json) ..."
                        printf "%s\n" "${DIR_FILES[@]}" \
                          | xargs -P4 -n1 -I{} bash -c 'import_dir "{}"'
                        
                        echo "==> Importiere Skripte (*.json) ..."
                        printf "%s\n" "${SCRIPT_FILES[@]}" \
                          | xargs -P4 -n1 -I{} bash -c 'import_script "{}"'
                        
                        # Fortschrittsanzeige beenden
                        wait "$PROGRESS_PID"
                        
                        echo -e "\n==> Import abgeschlossen: $TOTAL Objekte."
                        
                        echo "==> Starte Adapter: $ENGINE_INSTANCE"
                        [[ $DRY_RUN -eq 1 ]] || iob start "$ENGINE_INSTANCE"
                        
                        echo "==> Fertig."
                        
                        V 1 Reply Last reply Reply Quote 0
                        • V
                          Vippis @Vippis last edited by Vippis

                          @Marc-Berg @OliverIO

                          Könnt ihr mir sagen wie ich vom mqtt-client username/passwort und host setzen kann?

                          Alles bis auf Passwort kann ich so setzen:

                          docker exec -u 0 "${MQTT_CID}" iobroker object extend "system.adapter.${MQTT_ADAPTER}" "$(cat <<EOF
                          {
                            "native": {
                              "type": "client",
                              "host": "mosquitto",
                              "port": 1883,
                              "clientId": "${MQTT_CLIENT_ID}",
                              "username": "${MQTT_USER}",
                              "password": "${MQTT_HASH}",
                              "prefix": "",
                              "publishAll": false,
                              "keepalive": 60,
                              "clean": true,
                              "qos": 0,
                              "retain": false,
                              "subscribe": "#",
                              "ssl": false
                            }
                          }
                          EOF
                          )"
                          
                          

                          Das Problem ist das Passwort, weil der Adapter einen Hash will, den nur die GUI erzeugt

                          OliverIO 1 Reply Last reply Reply Quote 0
                          • OliverIO
                            OliverIO @Vippis last edited by

                            @vippis

                            Dann musst du in den Adapter schauen was die gui des Adapters mit dem Passwort macht, was der Nutzer einträgt.

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post

                            Support us

                            ioBroker
                            Community Adapters
                            Donate

                            838
                            Online

                            32.2k
                            Users

                            80.9k
                            Topics

                            1.3m
                            Posts

                            3
                            12
                            190
                            Loading More Posts
                            • Oldest to Newest
                            • Newest to Oldest
                            • Most Votes
                            Reply
                            • Reply as topic
                            Log in to reply
                            Community
                            Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                            The ioBroker Community 2014-2023
                            logo