Normalerweise nutzt man die VIS Oberfläche um den Status von Geräten oder Aktoren darzustellen oder mit ihnen zu interagieren.
Warum aber sollte man sie nicht auch zur Interaktion von Befehlen nutzen?
Ich stelle Dir hier die Möglichkeit vor, die System Updates, welche für den Raspberry Pi vorliegen, mit einem Klick zu installieren und dies auch in einem Statusfenster zu verfolgen.

Hinweis: Dieses Skript setzt die Verwendung von “ioBroker Skript zur Anzeige der benötigten System Updates des Raspberry Pi” voraus.

Skript

Zuerst erstellst Du ein neues Javascript im Bereich common.
Dieses Skript bitte nicht starten.

/*
 * @copyright 2020 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * @author 2020 Stephan Kreyenborg <stephan@kreyenborg.koeln>
 *
 * Dieses Skript dient zur freien Verwendung in ioBroker zur Verbrauchserfassung der Shelly Geräte.
 * Jegliche Verantwortung liegt beim Benutzer. Das Skript wurde unter Berücksichtigung der bestmöglichen Nutzung
 * und Performance entwickelt.
 * Der Entwickler versichert, das keine böswilligen Systemeingriffe im originalen Skript vorhanden sind.
 *
 * Sollte das Skript wider Erwarten nicht korrekt funktionieren, so hast Du jederzeit die Möglichkeit, Dich auf
 * https://www.kreyenborg.koeln
 * für Unterstützung zu melden. Jedes Skript besitzt seine eigene Kommentarseite, auf der,
 * nach zeitlicher Möglichkeit des Autors, Hilfe angeboten wird. Ein Anrecht hierauf besteht nicht!
 * 
 * Ansprüche gegenüber Dritten bestehen nicht. 
 * 
 * Skript Name:		APT Update installieren
 * Skript Version:	1.2
 * Erstell-Datum:	02. April 2021
 * 
 */

// Kommandos
var command_update = "sudo apt update";
var command_anzahl_updates = "apt list --upgradable 2>/dev/null | wc -l | awk '{print $S1-1}'";
var command_upgrade = "sudo apt-get -y upgrade";
var anzahl_updates = 0;

// Datenpunkt anlegen
var DataPoint = 'Systeminfos.ioBroker.raspi_updates_ausgabe';
createState(DataPoint, "", true, {
    name: 'Raspi Updates Ausgabe',
    desc: 'Ausgabe Systemupdates für den Raspi',
    type: 'string',
    unit: '',
    role: 'value'
},
    function () {
        installiere_updates();
    }
);

function installiere_updates() {
    // Paket-Update
    exec(command_update);
    update_datenpunkt("Prüfe auf neue Updates ...");

    // Anzahl neuer Updates
    exec(command_anzahl_updates,
        function (error, stdout, stderr) {
            if (stdout == '0') {
                anzahl_updates = 0;
            } else {
                anzahl_updates = parseInt(stdout);
            }
            if (anzahl_updates > 0) {
                log("Neue Updates: " + anzahl_updates + "<br>Neue Updates werden installiert. Bitte warten ...");
                update_datenpunkt("Neue Updates: " + anzahl_updates + "<br>Neue Updates werden installiert. Bitte warten ...");
                exec(command_upgrade, function (error, stdout, stderr) {
                    if (stdout.includes("autoremove")) {
                        update_datenpunkt("Alle Updates wurden installiert!<br>Es wurden nicht benötigte Pakete gefunden!<br><br>Fenster kann geschlossen werden!");
                    } else {
                        update_datenpunkt("Alle Updates wurden installiert!<br><br>Fenster kann geschlossen werden!");
                    }

                    // Beende Skript
                    setState("javascript.0.Systeminfos.ioBroker.raspi_updates", "0");
                    setState("javascript.0.scriptEnabled.common.APT_Update_installieren", false);
                });
            } else {
                update_datenpunkt("Keine neuen Updates zum Installieren!<br><br>Fenster kann geschlossen werden!");
                // Beende Skript
                setState("javascript.0.Systeminfos.ioBroker.raspi_updates", "0");
                setState("javascript.0.scriptEnabled.common.APT_Update_installieren", false);
            }
        });
}

function update_datenpunkt(text) {
    var tmp_text = getState(DataPoint).val;
    var neuer_text = tmp_text + "<br>" + text;
    setState(DataPoint, neuer_text, true);
}

Nachdem Du das Skript erstellt hast, musst Du die Zeile 68 im Skript auf den Namen anpassen, da dies für die Beendigung notwendig ist. Schaue dazu bitte in den Datenpunkt:

javascript.0.scriptEnabled.common

und kopiere Dir den Namen des Datenpunkt in die Zwischenablage.

Skript Datenpunkt
Skript Datenpunkt

Diesen Datenpunkt fügst Du nun in Zeile 68 ein. Standardmäßig ist dieser auf den Namen de Skripts gesetzt.

setState("javascript.0.scriptEnabled.common.APT_Update_installieren", false);

Dieses Skript dient im weiteren Verlauf zur Darstellung in VIS und beinhaltet das Prüfen auf Updates und das Installieren von Updates.

Integration in VIS

Vorbereitung

Zuerst erstellst Du eine eigene View mit dem Namen “APT_Update”. In diese View ziehst Du ein HTML Widget. Dieses HTML Widget bekommt als Text den Datenpunkt aus Zeile 34. Solltest Du diesen Datenpunkt angepasst haben, so musst Du ihn in VIS auch entsprechend anpassen. Die geschweiften Klammern vorne und hinten müssen zwingend angegeben werden, da sonst nur der Text und nicht der Datenpunkt ausgegeben wird.

{javascript.0.Systeminfos.ioBroker.raspi_updates_ausgabe}
Neue View APT_Update mit HTML Widget
Neue View APT_Update mit HTML Widget

Eigentlicher Aufruf

Damit Du nun diese View aufrufen kannst, benötigst Du in deiner “Haupt”-View ein “jqui – container – Button – view” Widget. Dieses ziehst Du an die Position, von wo aus Du das Update gerne starten wollen würdest.

Folgende Werte habe ich in meinem Widget gesetzt:

Widget Einstellungen

Als Objekt ID gibst Du den Datenpunkt aus Zeile 68 des Skriptes an und als Viewname verwendest Du den Namen der eigentlichen View. In meinem Beispielt ist dies “APT_Update”. Der Knopftext ist frei wählbar und kann heissen, wie Du gerne möchtest 😉

Wenn Du nun deine View aufrufst, kannst mit einem Klick auf den Button den Update Prozess in der VIS Oberfläche auslösen und in der Statusausgabe des Widget verfolgen, was passiert.

APT Update Ausgabe
APT Update Ausgabe

29 Kommentare

  1. Hallo Stephan,

    erstmal Vielen Dank für deine Arbeit und diese Seite – habe hier schon sehr viel Inspiration gefunden 🙂

    Ich bin mir nicht sicher ob ich etwas falsch mache, aber die in deiner Beschreibung angegebenen Zeilen “68” und “34” sind bei mir anders, wobei das eigentlich auch nicht am Zeilenumbruch liegen kann, aber ich habe das Script bei mir nun auch “APT Update installieren” genannt somit musste ich hier nichts weiter ändern.
    Beim Klick auf den Update Button kommt im Log folgende Ausgabe:

    2021-09-17 13:34:56.655 info Stop script script.js.common.APT_Update_installieren
    2021-09-17 13:34:56.630 warn at Pipe. (net.js:675:12)
    2021-09-17 13:34:56.630 warn at Socket.EventEmitter.emit (domain.js:483:12)
    2021-09-17 13:34:56.630 warn at Socket.emit (events.js:314:20)
    2021-09-17 13:34:56.629 warn at Socket. (internal/child_process.js:444:11)
    2021-09-17 13:34:56.629 warn at maybeClose (internal/child_process.js:1022:16)
    2021-09-17 13:34:56.629 warn at ChildProcess.EventEmitter.emit (domain.js:483:12)
    2021-09-17 13:34:56.628 warn at ChildProcess.emit (events.js:314:20)
    2021-09-17 13:34:56.628 warn at ChildProcess.exithandler (child_process.js:299:7)
    2021-09-17 13:34:56.628 warn at script.js.common.APT_Update_installieren:74:17
    2021-09-17 13:34:56.627 warn at setState (/opt/iobroker/node_modules/iobroker.javascript/lib/sandbox.js:1439:20)
    2021-09-17 13:34:56.623 warn State “javascript.0.Systeminfos.ioBroker.raspi_updates” not found
    2021-09-17 13:34:55.790 info script.js.common.APT_Update_installieren: registered 0 subscriptions and 0 schedules
    2021-09-17 13:34:55.753 info Start javascript script.js.common.APT_Update_installieren
    2021-09-17 13:34:55.721 info State value to set for “javascript.0.scriptEnabled.common.APT_Update_installieren” has to be type “boolean” but received type “string”

    Ich bin mir nicht sicher ob hier “State “javascript.0.Systeminfos.ioBroker.raspi_updates” not found” relevant ist da zur Zeit keine Updates verfügbar sind.
    Die Ausgabe scheint jedenfalls zu funktionieren.

    Jetzt fehlt mir aber im VIS die Ansicht wie oben zu sehen mit “System Updates: 0” ?
    Wie kann ich mir diese Anzeige einblenden lassen ?

    Vielen Dank für deine Hilfe!
    Viele Grüße

    • Hallo Martin,
      danke für Deinen Kommentar. Hier scheint es, das der Datenpunkt nicht erstellt werden kann.
      Kannst Du in deiner Objekt-Struktur einmal schauen, ob der Datenpunkt tatsächlich nicht vorhanden ist?

      Ansonsten kannst Du ihn selbst anlegen und nochmal testen.

      Gruß,
      Stephan

  2. Hallo Stephan,

    vielen Dank für Deine tolle Arbeit. Dieses Skript ist etwas, was sicherlich viele gut gebrauchen können.
    Ich habe leider nur 1 kleines Problem. Mit deinem Skript bekomme ich angezeigt, dass 1 Update verfügbar ist. Nachdem ich die Installation gestartet habe, kommt auch nach einer kurzen Zeit die Meldung, dass alle Updates installiert sind und das Fenster geschlossen werden kann. Wenn ich das Ganze aber prüfe, wurde keine Update installiert. Das 1 Update wird weiterhin angezeigt.
    Hast du evtl. eine Idee, was ich falsch gemacht haben könnte?

    Viele Grüße
    Gregor

    • Hallo Gregor,
      kannst du auf dem Gerät einmal schauen, was installiert werden soll?
      apt list --upgradable

      Dann können wir vielleicht schauen, wo das Problem liegt.

      Vielen Dank!

      Gruß,
      Stephan

  3. Hallo Stephan,

    danke für deine schnelle Reaktion. Ich habe mal nachgeschaut. Auf meinen Raspi wird folgendes gezeigt:

    python-sense-emu-doc/testing 1.2-1 all [aktualisierbar von: 1.1.2]
    N: Es gibt 1 zusätzliche Version. Bitte verwenden Sie die Option »-a«, um sie anzuzeigen.

    Ich hoffe das hilft weiter.

    Viele Grüße
    Gregor

  4. Hallo Stephan,

    danke für deine schnelle Reaktion. Ich habe mal nachgeschaut. Auf meinen Raspi wird folgendes gezeigt:

    python-sense-emu-doc/testing 1.2-1 all [aktualisierbar von: 1.1.2]
    N: Es gibt 1 zusätzliche Version. Bitte verwenden Sie die Option »-a«, um sie anzuzeigen.

    Ich hoffe das hilft weiter.

    Viele Grüße
    Gregor

  5. Hallo Stephan,
    was müsste denn in Zeile 34 stehen? Die Zeilennummern stimmen leider aufgrund des Kopierens nicht überein. Bei mir steht in Zeile 34:

    desc: ‘Ausgabe Systemupdates für den Raspi’,

    das meinst du aber garantiert nicht.
    Kann es sein, dass du die Zeile exec(command_update); meinst. Wie sollte das dann aussehen?

    Viele Grüße
    Gregor

  6. Hallo Stepphan,
    das scheint leider nicht zu helfen. Das Skript findet 1 Update, meldet das es installiert wird, meldet “bitte warten” und dann das Alle Updates installiert wurden. Die Meldung “Fenster kann geschlossen werden” kommt allerdings nicht. Auch sehe ich auf dem Raspi noch das Update.

    Viele Grüße
    Gregor

  7. Hallo Stephan,
    der Skript ist ja nicht gestartet. Er wird ja über den Button neu aufgerufen.
    Auf dem Raspi erhalte ich:
    E: Befehlszeilenoption »a« [aus -a] kann in Kombination mit den anderen Optionen nicht interpretiert werden.

    Viele Grüße
    Gregor

    • Hallo Gregor,
      dann scheint es genau bei dem Paket nicht zu gehen. Dies kommt ab und an vor, wenn sich das Repository ändert und somit die Version von einer anderen Quelle kommt.
      Das Paket muss dann einmal händisch aktualisiert werden. Eben mit “-a” bei “sudo apt-get upgrade”

      Gruß,
      Stephan

  8. Hallo Stephan,
    vielen Dank für deine Hilfe.
    Ein echt tolles Tool, auch wenn hier mal im Einzelfall ein Packet per Hand aktualisiert werden muss.
    Ein schönes Wochenende.

    Viele Grüße
    Gregor

  9. vielen Dank für das tolle Tool, kannst du mir vielleicht auch sagen wie ich es statt in VIS in iQontol integrieren könnte?

    Gruß Björn

  10. Danke für das Skript bzw. die Skripte – wie kann man es denn modifizieren, wenn man ein Multihostsystem nutzt und neben dem Master auch die Slaves aktualisieren möchte? Bsp. der Master hat die IP 192.168.1.10 und der 1. Slave die 102.168.1.11. Wie kann dann das Skript auch auf dem Slave ausgeführt werden?

    Danke
    Marcus

    • Hi Marcus,
      du könntest Zeile 26,27 kopieren und als neue Variablen anlegen. Diesen Aufruf dann via ssh an das Slavesystem und den Rückgabewert dann auf dem Host verwenden.

      Gruß,
      Stephan

      • ähm… ok, ich bin leider nicht so fit mit Linux. Ich kapiere soweit die Syntax, aber wie genau kann ich mich mittels ssh im skript auf meinen slvae aufloggen und dann dort die Befehle ausführen? Ich habe es probiert, bekomme aber die Ausführung nicht auf dem slave hin, sondern immer auf meinem master (dort, wo das skript gestartet wird).

        • Hallo Marcus,
          um z.B. ein Kommando auf einem anderen System auszuführen und dessen Rückgabe zu erhalten, kannst Du folgendes Beispiel verwenden:


          root@system1:~ # ssh user@system2 date (Dies ist der Befehl)
          Fri Apr 22 15:02:02 CEST 2022

          Gruß,
          Stephan

          • ja, das war “leider” schon klar – nur wie binde ich denn den in die Reihenfolge des Programm Codes ein?
            das Problem ist doch das “anmelden” am slave – oder irre ich mich da? Es kommt ja immer eine PW-Abfrage.

            Ich habe nun Einiges schon gelesen und bin auf “sshpass” gestossen.

            führe ich z.B. in der Console auf meinem MasterPi diesen Befehl aus:
            sshpass -f /dev/null | wc -l | awk ‘{print $S1-1}’

            kommt die Anzahl der möglichen Pakete-Updates des slaves auch richtig heraus.

            Nutze ich diesen Befehl z.B. in deinem Skript, dann bekomme ich die Fehlermeldung:
            Error: Command failed: sshpass -f /dev/null | wc -l | awk ‘{print $S1-1}’ /bin/sh: 1: Syntax error: “(” unexpected

            Da komme ich einfach nicht weiter

          • zu früh auf absenden geklickt.

            wenn ich an der Konsole folgendes ausführe, kommt die richtige Anzahl heraus:
            sshpass -f /dev/null | wc -l | awk ‘{print $S1-1}’

    • ich kann die Befehlszeile nicht kopieren. Er schneidet immer einiges heraus…
      *sshpass -f /dev/null | wc -l | awk ‘{print $S1-1}’*

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.