NEWS

Javascript: gefährliches Halbwissen + Syntaxprobleme = Frust


  • Hallo auch,

    Nachdem mein System einigermaßen läuft, versuche ich mich in JS, da Blockly nicht alles kann.
    Aber ich musste gestern feststellen, das dies mit iobroker nicht so leicht ist.

    1. Doku ist nur bedingt zu gebrauchen, mir ist klar, das dafür die normalen User besser zu gebrauchen sind als die dvs, da diese lieber proggen sollte. Aber es gibt Anwendungen bzw Befehle die von den normalen Usern nicht unbedingt erklärt werden können.

    2. loggen ist nicht so leicht wie gedacht, ich wollte scheinbar ungewöhnliche Änderungen an der Stateauswahl verändern. Dies brachte mir einige Fehler bei der Auswahl der richtigen Syntax. Dabei ist mir aufgefallen, das die logs im javascript Adapter und die im Hauptlog unterschiedlich aufbereitet werden. " und ' werden unterschiedlich dargestellt, aber um dann noch mehr zu verwirren sind die Anzeigen noch anders wenn man die Maus im Hauptlog über einen Eintrag hält oder dann noch in die Datei selbst schaut. Hatte zum Schluss 3 Tabs offen, und musste versuchen daraus Fehler zu beseitigen.

    3. einige Syntaxfehler werden im Editor zwar angezeigt, aber nicht erläutert bzw genauer angezeigt, rechts war ein kleiner roter Balken, dieser war aber keiner Zeile zuzuordnen.

    4. Javascript extrem langsam und Neustart, irgendwie muss ich dabei ein script in ein Loop geschickt. Da ich dann das Script beendet hatte, war für mich das Thema erledigt, für iobroker war dies aber nicht der Fall. Zum Schluss startete der javascript Adapter dauerhaft neu mit Fehler 156. Scripte beenden brachte keinen Erfolg, auch Host starten nicht, nur iobroker komplett beenden und starten half. sollte iobroker das nicht auch selbst schaffen, solche loops zu erkennen und zu beenden?

    Normalerweise war ich vorher der Meinung das ich als user nichts kaputt machen kann, dies ist aber scheinbar nicht der Fall.
    Darf ich js scripte wirklich nur auf einem zusätzlichen Testsystem prüfen um nichts zu zerschießen, egal wie simpel diese vorher eigentlich aussehen?
    Wieso zeigt das log nur Fehler 156, aber keine genauere Zuordnung?


  • e-s sagte:

    Doku ist nur bedingt zu gebrauchen

    Welche Doku ?

    e-s sagte in Javascript: gefährliches Halbwissen + Syntaxprobleme = Frust:

    dabei ein script in ein Loop geschickt. Da ich dann das Script beendet hatte, war für mich das Thema erledigt, für iobroker war dies aber nicht der Fall.

    Ja, es kann sehr lange dauern, bis die gespeicherten Subscriptions alle abgearbeitet sind. ioBroker stoppen und neu starten ist schneller.

    e-s sagte in Javascript: gefährliches Halbwissen + Syntaxprobleme = Frust:

    sollte iobroker das nicht auch selbst schaffen, solche loops zu erkennen und zu beenden?
    Normalerweise war ich vorher der Meinung das ich als user nichts kaputt machen kann

    Einen Schutz gegen programmierte Endlos-Schleifen gibt es nicht. Die Scripte werden von Node.js (V8) übersetzt und abgearbeitet.

  • Starter

    Hallo e-s , mit Werkzeugen ist es so eine Sache. Man sollte zur Nutzung genug Wissen und Erahrung haben, damit man damit nichts kaputt macht. Wer die ersten Schritte mit einem Werkzeug macht, muss immer damit rechnen, dass etwas nicht so klappt, wie man sich das vorgestellt hat. Kein Schreiner macht sein Meisterwerk im ersten Monat. Zunächst muss der Umgang mit den unterschiedlichen Werkzeugen, der Auswirkung der Werkzeuge auf das Material und die präzise Arbeit erlernt werden.

    In der EDV ist das auch nicht anders. Keiner hat nach einem Tag mit einer Programmiersprache einen kompletten Compiler oder ein komplexes GUI gebaut.
    Der eine liebt seine Windows-Oberfläche, um mit der Maus in geführter Form seine Arbeit zu erledigen. Der andere braucht ein Terminalfenster ohne Maus und erledigt das gleiche auf andere Art.

    So ist es auch bei der Programmierung in ioBroker: Blockly ist eine relativ einfache Umgebung, die dem Anwender vieles an möglichen Fehlern (hauptsächlich syntaktische) abnimmt. JS ist da wesentlich offener und macht keine so stringente Prüfungen.
    Genau das ermöglicht dann weitaus mehr (syntaktische und semantische) Fehler.

    Man lernt hoffentlich mit den und aus den Fehlern. Und hier gibt es Unterstützung, wenn man Fragen hat.


  • Ich verwende Node-Red als Logikmaschine. Da brauchst zwar auch JS Kenntnisse, kommst aber in den meisten Fällen auch ohne aus. Wenn Du noch keine Script‘s erstellt hast, würde ich es mir anschauen bevor Du Dich endgültig entscheidest.

  • Starter

    Nach Fehler 156 habe ich auch schon gesucht und in der doku nicht gefunden.
    Erst ganz tief im sourcecode von iobroker js-controller habe ich es dann gefunden.
    Für Anfänger das zu finden, sehe ich keine Chance

    156 is special code that adapter wants itself to be restarted immediately

    https://github.com/ioBroker/ioBroker.js-controller/blob/f8c4c7d2d90befd3557dd9747f5bef62e547faba/main.js#L3245

    und

    https://github.com/ioBroker/ioBroker.js-controller/blob/fd3648bb3a5200aa294f6931266f80c4729b013d/lib/exitCodes.js#L38

    Das ist kein echter Fehler sondern beabsichtigtes Verhalten.
    Bei mir taucht der immer dann auf, wenn man die adapter configuration ändert und wieder in den entsprechenden Status schreibt. Dann startet iobroker den entsprechenden Adapter automatisch neu.

  • Starter

    e-s
    Bei den anderen Punkten musst du konkreter werden. Am besten mit Codebeispielen, was du wo gemacht hast.
    Wie die Reaktion des Skripts war und was du eigentlich erwartest. Dann kann man helfen.
    bis auf die code 156 Frage könnte ich dir, mangels Details, hier nicht weiterhelfen.


  • OliverIO paul53 hans_999

    Ok, dann will ich mal etwas zu meinem Projekt erzählen, um es besser verdeutlichen zu können.
    Ich nutze für für unterwegs und zur schnellen Kontrolle den iogo Adapter und die dazugehörige App. Ich mag kein VIS und brauche auch keine bunten Felder. Klarer kurzer Text. iogo zeigt alle DP die ein enum hat. Das werden mir langsam aber zu viele DP die ich schnell im Blick haben will. Deswegen habe ich mir einige scripts gebaut die mehrere Gruppen zu einer Tabelle zusammenführen.
    Beispiel: Jetzt gab es einen thread über shellys und deren Temperatur, schnell habe ich dann zum Test eine Warntemperatur erstellt um nicht ständig mir die Zahlen ansehen zu müssen. Die Grundtemperaturen sind aber Grund verschieden, je nachdem wo der shelly verbaut wurde.
    Also will ich in dem array noch für jeden shelly eine eigene Warntemperatur einstellen können. Dies will ich auch schon seit langem auch für Warnzeiten von Verbrauchern machen, aber mir fehlte noch die nötige Idee. die aber nicht übermäßig viele DP verschlingt.

    Diese Idee ist jetzt also ein dynamisches Menü aus DP. Struktur kommt dann später. Mir war aber nie klar wie ich die common.states schnell und einfach verändern kann. Dabei soll aber nicht das State selbst sondern eben die Auswahlmöglichkeit verändert werden. Durch Zufall habe ich dann einen Thread gesehen wie man Dinge im DP anpassen kann.

    Hier also das beisherige testscript:

    function listsGetSortCompare(type, direction) {
      var compareFuncs = {
        "NUMERIC": function(a, b) {
            return parseFloat(a) - parseFloat(b); },
        "TEXT": function(a, b) {
            return a.toString() > b.toString() ? 1 : -1; },
        "IGNORE_CASE": function(a, b) {
            return a.toString().toLowerCase() > b.toString().toLowerCase() ? 1 : -1; },
      };
      var compare = compareFuncs[type];
      return function(a, b) { return compare(a, b) * direction; }
    }
    
    const IDs = Array.prototype.slice.apply($("channel[state.id=linkeddevices.0.Shelly_Temp.]")).slice().sort(listsGetSortCompare("TEXT", 1));
    const test = 'messwerte.0.Hilfsdaten.test';
    var anzahl = (IDs.length - 1);
    var Werteliste = [];
    var Wertezeile = [];
    
    
    for(let i = 0; i < IDs.length; i++) {
        let id = IDs[i];
        let name = getObject(id).common.name;
       //if (i != anzahl) {
       //     Wertezeile = ['"',i,'": "',name,'",'].join(''); //hier war ich noch der Meinung die , am Schluss selbst hinzufügen zu müssen
       // } else {
       //     Wertezeile = ['"',i,'": "',name,'"'].join('');
       // };
        var Wertezeile = [i,'": "', name].join(''); //hier wurde ich dann sehr dirty
        console.log(Wertezeile);
        Werteliste[(i)] = name;
    };
     
    
    
    
    console.log(Werteliste.join('\n'));
    //extendObject(test,{common: {states: {      "0": "eins",
    //      "1": "zwei"}}});  //das ist die Form wie es aussehen sollte
    extendObject(test,{common: {states: Werteliste}});
    console.log (getObject(test).common.states);
    
    
    

    die erste Funktion sortiert nur nach Namen. Die auskommentierten Stellen sind frühere Versuche, die aber nur Probleme machten.
    Die ersten Tests haben mir dann verdeutlicht, das leider ' " ' niemals das " so reinkommt wie man es will, denn es wird automatisch ein / davor gesetzt.
    Das ganze reinsetzen wird auch mit [ ] anstatt { } , durch das testen wie man andere Klammer setzt hatte ich das System dann mal gekillt.
    klammern.png
    Wie man hier sehen kann, werden nämlich die : nicht erlaubt, das geht nur mit den { } Klammern.

    Wie man ganz unten sehen kann, will ich ein Auswahl mit Zahl und dem richtigen Begriff, leider setzt er von alleine immer um jeder Zeile eigene " ", deswegen habe ich in der "dirty" Zeile die " Bereiche unterbrochen, klappte aber wegen den / auch nicht.

    Ich schätze die join('') machen mir auch Probleme, hab aber keine Ahnung wie das anders gehen soll. Wenn man sich die ganzen console.logs ansieht, dann fällt einem auf, das das log meist dann " anzeigt, wenn man aber die Maus über die Zeile im log hält, dann wieder nur ' ankommen.

    In dem Objekt selbst sieht es manchmal dann wieder ganz anders aus.

    wenn ich pro Zeile nur name reinsetze, dann klappt das auch recht gut, aber ich hätte eben im DP lieber eine Nummer zur Weiterverarbeitung als den Namen selbst.

    So sieht das dann in iogo aus:
    Screenshot_20200326-191948_iogo.jpg Screenshot_20200326-191936_iogo.jpg

    Ich hoffe ihr könnt meiner Idee einigermaßen folgen und habt eine Idee.
    Danke schon mal


  • e-s sagte:

    habt eine Idee.

    Prinzip:

    var Werteliste = {};
    for(let i = 0; i < IDs.length; i++) {
        let id = IDs[i];
        Werteliste[i] = getObject(id).common.name;
    }
    log(JSON.stringify(Werteliste)); // Format wie im Tab "Objekte" unter RAW
    let obj = getObject(test);
    obj.common.states = Werteliste;
    obj.common.max = IDs.length - 1;
    setObject(test, obj);
    

  • paul53
    Danke, mal wieder.....

    Klappt natürlich so wie es soll.

    Aber das ist genau das was ich meine, dein Code ist wieder so simpel, das es mich aufregen könnte, aber ich weiß genau das ich nie auf diese Idee gekommen wäre.
    Ich mag es nicht, immer sofort zu fragen anstatt selbst den Kopf zu nutzen, aber es bleibt mir wohl keine andere Wahl.
    Genau das meinte ich mit Doku, wo kann ich sowas nachlesen.
    Hatte mal bei kindle unlimited ein JS Buch gelesen, aber das geht irgendwann nur noch in Richtung HTML, nichts mit DP wie sie iobroker. Und bei iobroker finde ich eben nie etwas zu solch speziellen Problemen.


  • e-s sagte:

    Doku, wo kann ich sowas nachlesen.

    Ich nutze meist selfhtml zum Nachlesen.

  • Starter

    die kunst ist die frage richtig bei google einzugeben.
    Was mir bei deinem ersten skript aufgefallen ist.
    du solltest dich nochmal mit den unterschieden von Objekten und Arrays beschäftigen.
    In Zeile 17, ich vermute du willst Werteliste initialisieren ist das x etwas komisch.
    Das bedeutet, das du ein Array anlegen willst und erst einmal genau ein Element enthält, nämlich x (als variable, nicht als Wert.
    Da x aber nicht existiert, dürfte das erste Element in diesem Array undefined sein.

    Dann bei dem nächsten bild mit den states.
    Wenn du ein Array anlegst, und der Index ist durchgängig bzw. dir egal was es für eine Nummer ist, dann reicht
    ["wert1","Wert2","Wert3"] javascript indiziert dann selber
    Wenn du den Index selber benennen möchtst und es ist entweder keine Zahl oder nicht aufsteigend von 0, dann ist es streng genommen kein Array mehr, sondern ein Objekt. d.h. Array-Schleifen (bsp forEach oder for(;;)) funktionieren dann nicht mehr, sondern man muss Objektschleifen (for item in objekt) nehmen.

    Durch die hohe flexibilität von javascript (automatische typumwandlung) entstehen of Probleme, wenn man die magie hinter javascript nicht kennt. Daher wird für den profieinsatz auch gern Typsichere Sprachen verwendet.

    Deswegen ist es gut mit einem debugger zu arbeiten. Den gibt es so nicht für die iobroker javascript engine.
    Wenn ich mit Skripten arbeite (ich versuche das zu vermeiden), dann baue ich mir das Gerüst meist im Browser auf, dort wo iobroker Spezial kommt, belege ich dumme variablen vor und teste dann in ruhe dort mit debugger durch.


  • OliverIO
    Wo da auf einmal das X herkommt ist mir schleierhaft, bei mir im script war es das nicht.
    Danke nochmal, versuche weiter zu lesen.

    Für mich war ja eben auch die Frage, wie kann der Editor verbessert werden, da die externen Editoren wieder nicht die Besonderheiten von iobroker kennen.


  • e-s sagte in Javascript: gefährliches Halbwissen + Syntaxprobleme = Frust:

    Aber das ist genau das was ich meine, dein Code ist wieder so simpel, das es mich aufregen könnte, aber ich weiß genau das ich nie auf diese Idee gekommen wäre.

    Mit mehr Erfahrung schon, ich bin noch weit von paul53 entfernt und trotzdem fallen mir die Haare aus, wenn ich meine älteren Scripte anschaue. 🙂

  • Starter

    In der "Programmierkunst" gibt es u.a. zwei zentrale Komponenten

    • die Logik: Wie soll "etwas" ablaufen, damit ein bestimmtes Ziel erreicht wird. Hierzu werden Erfahrungen, Ideen, vielleicht sogar Intuition neben elementaren Kenntnissen benötigt (siehe auch die Anmerkung von ticaki). Hier muss man von klein (im Sinne von kleinen Aufgabenstellungen) auf anfangen. Ein Versuch, mit einem ersten Programm eine Super de Luxe Lösung zu "basteln", kann nur schief gehen.

    • der Code: Ähnlich wie beim Erlernen einer natürlichen Sprache musst Du auch die Elemente einer Programmiersprache erlernen (elementare Befehle, Datentypen, Objekte, ...). Ohne (bildlich gesprochen) "Vokabel lernen" geht dies nicht ab (siehe hierzu auch den Hinweis von OliverIO). Die Methode "Trial and Error" ist dabei eine bedeutsame Methode.

    Also: Nicht entmutigen lassen, aber erst mal mit kleineren Aufgabenstellungen anfangen.


  • mal eine kurze weitere Frage, habe heute 3 neue shellys verbaut und in iobroker integriert.
    ich erstelle ja eine Liste über:

    const IDs = Array.prototype.slice.apply($("channel[state.id=linkeddevices.0.Shelly_Temp.]")).slice().sort(listsGetSortCompare("TEXT", 1));
    

    durch ein einfachen neustart des scripts habe ich die neuen devices nicht in die Liste bekommen, erst als ich unter instances den javascript adapter neu gestartet habe, waren die neuen da.


  • e-s sagte:

    erst als ich unter instances den javascript adapter neu gestartet habe, waren die neuen da.

    Es ist ein bekanntes Problem, dass die Puffer der Javascript-Instanz nicht (immer) automatisch aktualisiert werden.

Suggested Topics

  • 12
  • 22
  • 2
  • 3
  • 19
  • 4
  • 23
  • 17

1.9k
Online

34.7k
Users

40.8k
Topics

558.5k
Posts