stefandreyer / CODESYS-MQTT

MQTT client library for CODESYS, supporting all QoS
MIT License
109 stars 24 forks source link

MQTT disconnected nach WLAN-Restart #22

Closed Tommilein closed 4 years ago

Tommilein commented 5 years ago

Hallo Stefan, mache mal einen neuen Eintrag auf, weil das nicht zu der anderen Problematik passt. Ich habe nun ein ganz anderes Problem. Bei einem WLAN-Restart connected sich MQTT nicht wieder - nicht mal nach Codesys-Neustart. Erst ein reboot hilft. Da ich aber nach dem WLAN-Restart wieder auf die Anwendung bzw. den Raspberry draufkomme, sollte die WLAN-Verbindung eigentlich stehen.

Beim WLAN-Restart starte ich per Systembefehl ein bash-script, das etwa so aussieht:

/sbin/ifdown 'wlan0' 
sleep 3
/sbin/ifup --force 'wlan0'

In der MQTT-Bibliothek wird ja viel mit dem Init-Flag gearbeitet. Das initialisiert ja nie wieder etwas, wenn das Programm läuft ( und nur auf Betriebssystem-Ebene etwas passiert).

Ursache für diesen Restart sind immer wieder lange Antwortzeiten im WLAN, denen ich noch nicht auf die Spur gekommen bin (und mit denen ich nicht allein auf der Welt zu sein scheine). Der Restart hat dies aber immerhin wieder abgestellt.

Dieses Verhalten hat auch Deine ältere Lib-Version gezeigt. Deshalb bin ich überhaupt auf die neue Version umgestiegen - in der Hoffnung, das das Problem dort nicht auftritt, leider...

MQTT_Disconnected_2

Unklar ist mir, warum noch nicht mal ein Codesys-Neustart hilft (codesyscontrol stot und start).

Hast Du eine Ahnung, wo man da suchen kann ??

Viele Grüße Thomas

stefandreyer commented 5 years ago

Hallo Thomas, ja das sagt mir was. Mein raspi läßt sich auch ab und zu nicht per codesys aber per SSH erreichen. Läuft auch über WLAN. Aber alles ausgehende funktioniert, also SQL und mqtt. 

Was ich in so einem zustand schon mal gesehen hatte war das er den DNS Namen nicht mehr auflöste. Sieht man im mqtt_controll. Das hatte sich aber nach Zeit x wieder gefangen. Die Auflösung ist eine system Funktion. Weis nicht was da hängt. Schau mal obs bei dir das gleiche ist. Grüße Stefan

Tommilein commented 5 years ago

Hallo Stefan,

setze nicht immer soviel voraus ... was ist mqtt_controll ???

Hilf mal schnell, bitte. Manchmal stehe ich auch auf dem eigenen Schlauch. Grüße

stefandreyer commented 5 years ago

Ein FB der im handle_mqtt aufgerufen wird. Der handelt die Verbindung aus. Wird ganz unten aufgerufen... Rechtsklick, gehe zur Definition, wiederholen, anschauen...

Tommilein commented 5 years ago

Schaue ich mir an...

Tommilein commented 5 years ago

Hallo Stefan,

da bin ich wieder überfordert. Die Daten in MQTT_CONTROL sehen im Connect-Zustand nicht anders aus als im Disconnect-Zustand. Das ist vielleicht schon der Fehler. Evtl. Bekommt MQTT_CONTROL einen disconnect-Zustand gar nicht mit.

Im CONNECT-ZUSTAND: MQTT_Control_OK

MQTT_Control_NOT_OK

Das hier ist mir aufgefallen, weil der Kommentar eigentlich was anderes ausdrückt: MQTT_Control_NOT_OK_2

Müsste hier nicht FALSE stehen, wenn es keinen Connect gibt??

Im Kommentar steht ja was von "close with disconnect..." . Kannst Du Dir da einen Reim drauf machen. Mir kommt es so vor, als ob die MQTT-Lib den DISCONNECT-Zustand irgendwie nur ziemlich "weit oben" erkennt, aber keinen Neustart der Connection veranlasst - keine Ahnung wie das gehen soll.

Viele Grüße Thomas

Tommilein commented 5 years ago

Hallo, habe nochmal geschaut:

So sieht es im Handle im DISCONNECT-Zustand aus:

MQTT_Handle_1

weiter unten: MQTT_Handle_2

Ich kann im ganzen Handle nicht erkennen, das bei einem PingTimeout irgendwo der Zähler CountRepeatedPingDisconnect erhöht wird.

Damit kommt das Programm nie über "step = 10" weg und "DoDisconnect" wird nie TRUE.

Mit Forcen des Zählers auf 11 und step auf 40 habe ich wohl alles zum Durchlaufen der anderen Steps gebracht aber neu Connected hat er nicht. Da wird es wohl noch mehr Fallen geben. Aber das Ding mit dem nicht Erhöhen des Timeoutzählers ist doch nicht ganz koscher - oder ?

Ich hoffe, das hilft Dir das Problem zu erkennen. Falls es wirklich ein MQTT-Lib-Problem sein sollte, erklärt das aber nicht, das bei einem Codesys-Neustart auch kein neuer Connect erfolgt. U.U. werden ein paar Start-Flags nicht richt richtig gesetzt. Es werden ja wohl keine persistenten Variablen im Spiel sein.

Schau mal bitte, ob Du was findest, würde mir sehr helfen.

Grüße Thomas

stefandreyer commented 5 years ago

Mach ich.

stefandreyer commented 5 years ago

Hallo Thomas,

schau mal bitte ob du im disconnect status vom pi aus den broker anpingen kannst und was in URL_DATA steht.

Grüße

Tommilein commented 5 years ago

Hallo Stefan, Deine Mail habe ich nicht gleich gesehen, obwohl ich am Rechner saß. Wenn ich in einem Problem stecke, gucken nur noch die Füße raus...

Die Ping-Geschichten sind schon verquer. Im connect- und damit Normalmodus gehen die Pings zu google.de o.a. , aber nicht zu den Brokern:

ping_geht_nicht_3

Zu den Brokern geht aber nirgnds ein Ping (auch nicht von Windows aus). Es kommt aber auch nicht zum "Network error".

Wenn ich das WLAN restarte ist es tatsächlich so, das dann gar nichts mehr geht.

ping_geht_nicht_1

Für "Ping" ist das Netzwerk nicht erreichbar. Wohl aber für ssh und die Codesys-Visualisierung u.a.

Am Ende ist es dann noch schlimmer. In 3 von 4 Fällen gehen ssh und die Visualisierung nach einem "shutdown -r now" nicht los, ich komme nicht direkt in den Raspberry rein. Das er aber normal lebt, erkenne ich, wenn ich ein remote ssh auf diesen Raspberry mache, da zeigt sich z.B. der aktuelle Inhalt des syslog-Files.

ping_geht_nicht_2

Ich muss den Raspberry richtig stromlos machen, ehe ein reboot auch das WLAN wieder aktivieren kann. Ich denke, das dieses "/sbin/ifup --force 'wlan0" nicht richtig funktioniert. Das kann eine Menge Ursachen haben: falsch installiert oder konfiguriert oder,oder... Die Tatsache, das der WLAN-Adapter noch einen Teil seiner Arbeit tut (remote ssh), geht komplett über mein Verständnis. Den Unterschied zwischen ssh via putty und ssh remote vom Raspberry kenne ich weiß Gott nicht. Geschweige denn von Ping's , die nur so halb gehen.

Ich habe langsam den Glauben an WLAN verloren. Das macht mir zuviel Sorgen mit seinen ständigen Ausfällen.

Eigentlich muss ich Dich jetzt aus der MQTT-Problemstellung entlassen. Ich müsste erst mal ein richtiges "WLAN-restart" hinbringen. Aber vielleicht weißt Du auch zu diesem Elend einen Rat.

Hattest Du überhaupt die Möglichkeit, den WLAN-Reconnect nachzustellen?

Viele Grüße Thomas

stefandreyer commented 5 years ago

Hallo Thomas,

wie geschrieben, der PI ist regelmäßig nicht erreichbar. Er füllt aber weiter brach die Datenbank und versendet MQTT Telegramme. Ich starte dann meine Router neu und alles geht wieder.

Da er nur im WLAN hängt kann ich diesen reconect noch nicht nachstellen. Müsste ich mir erst was zum Probieren aufbauen. Scheint ja aber n Rasbien Problem zu sein. Meiner wird auch deswegen ans LAN wechseln.

Grüße Stefan

Tommilein commented 5 years ago

Hallo Stefan,

es ist eine Crux. Wahrscheinlich liegt das Problem wieder mal an denen, die vor dem Computer sitzen.

An einem 2. Raspberry (auch noch der, den ich immer zum testen nehme) funktioniert alles wie es soll.

MQTT_funktioniert

Nun kann ich nur starre Bilder hier reinstellen, die nicht so richtig andeuten, das das MQTT über den WLAN-Restart hinaus funktioniert. Aber es soll ja auch mehr der Beweis sein, das Deine Library funktioniert. der Connect zu den Brokern über den Restart hinaus bleibt erhalten.

Und zu guter letzt habe ich zwischen ifdown und ifup nochmal 15s Pause gemacht und ich sehe, das die Broker-Connect-Anzeige kurz mal auf "disconnect" gegangen ist. Das ist der Beweis, das Deine Lib auch wieder Reconnected - wie immer sie das auch macht, gratuliere.

Nur den WLAN-Fehler auf meinem "richtigen" Raspberry werde ich wohl nicht wegbekommen. Diese update/upgrade/install-Prozeduren sind nicht meine Welt. Und sie lassen immer irgendwelchen Müll übrig, an dem sie dann selbst beim nächsten Mal hängenbleiben. Wird wohl eine Grundinstallation notwendig.

Viele Grüße Thomas

Tommilein commented 5 years ago

Hilfe !!

Hallo Stefan, ich habe jetzt einen ganz blöden Effekt. Seit 19.7. also ca. 4 Tage schreibt mein raspberry beim Shutdown keine persistenten Variablen mehr in die Application.ret. Ich habe schon den ganzen Tag über gesucht. Zum Beispiel mit zurückziehen von Abzügen des kompletten Raspberries. Mit dem aktuellen Programm hilft das nix. Und jetzt kommts: Nehme ich ein programm mit der alten MQTT-Bibliothek gehts. Dann wird das Schreibdatum des Files schön hinterher gezogen.

Mit der neuen Bibliothek steht der Timestamp des Files wie Ochs. Und natürlich wird bei jedem Neustart initialisiert. Da die Raspberries immer mal wieder hochgezogen werden, ist das ein Riesenelend.

Nun kann das nicht an der Lib liegen. Ich hatte sie ja schon vorher installiert und benutzt. Aber kannst du Dir vielleicht vom Grunde her einen Reim darauf machen, welchen Zusammenhang ich da hergestellt habe??

Das Schlimme ist, das ich einen alten Betriebssystem-Abzug vom Raspberry eingesetzt habe und mit dem neuen Programm geht es trotzdem nicht - unverständlich. Ich kann mir nur vorstellen, das ich was an der Developer-Umgebung verändert habe und das dort die Ursache liegt. Das Einzige ist der dynamische Speicher.... Darf der beliebig groß sein. Ich habe es mit 100kB und mit 5Mbyte versucht - kein Unterschied, keine persist vars gemerkt. Gabs noch wass Anderes ?

Hast Du eine Idee - einfach mal so ??

Viele Grüße Thomas

stefandreyer commented 5 years ago

Hallo Thomas,

ich weiß ja jetzt nicht wie du deine pesistenten variablen implementiert hast. Vielleicht kannst du den Prozess manuel anstarten und debugen?

Grüße Stefan

Tommilein commented 5 years ago

wie du deine pesistenten variablen implementiert hast so: VAR_GLOBAL PERSISTENT RETAIN

Also wie im Lehrbuch vorgesehen. Nichts besonderes eben. Aber ich habe mittlerweile herausbekommen, das ich wieder mal die Ursache bin.

Es hat nichts mit neuer und alter Bibliothek zu tun, sondern mit dem callback. Ich habe da wahrscheinlich ohne große Ahnung einen/mehrere Fehler eingebaut, die so eine komische Auswirkung haben. Da an dieser Stelle viel mit Pointern gearbeitet wird, ist das auch nichts aussergewöhnliches. Ich renne auch ab und zu in eine Exception, deren Ursache ich nicht erkennen kann.

In Anlehnung an deine Funktion "LampBase" habe ich diesen Code geschrieben.

SwitchTrigger(CLK:= SwitchIn);

IF NOT MyInit OR SwitchTrigger.Q THEN

    MyInit := TRUE;

    TextSend:=TextIn;
    IF Broker_Nr = 1 THEN

        Collector_1.put(instance:= THIS^);   // Diese Zeilen herausnehmen und die persistenen Vars bleiben erhalten

        gl_EmpfangsText_B1:='leer';
        MyTopicSend:=gl_MQTT_SendeTopic_B1;
        publish.SetMqttInOut(MQTT_IN_OUT:= ADR(GVL_MQTT.MQTT_IN_OUT_1));    // Parameter für "publish" an Broker 1 übergeben

    ELSIF Broker_Nr = 2 THEN
        Collector_2.put(instance:= THIS^);      // und diese hier
        gl_EmpfangsText_B2:='leer';
        MyTopicSend:=gl_MQTT_SendeTopic_B2;
        publish.SetMqttInOut(MQTT_IN_OUT:= ADR(GVL_MQTT.MQTT_IN_OUT_2));    // Parameter für "publish" an Broker 2 übergeben
    ELSIF Broker_Nr = 3 THEN
        Collector_3.put(instance:= THIS^);      // und diese hier
        gl_EmpfangsText_B3:='leer';
        MyTopicSend:=gl_MQTT_SendeTopic_B3;
        publish.SetMqttInOut(MQTT_IN_OUT:= ADR(GVL_MQTT.MQTT_IN_OUT_3));    // Parameter für "publish" an Broker 3 übergeben
    END_IF  

    MyTopicRecive:=gl_MQTT_Empfangs_Topic;

END_IF

IF SwitchTrigger.Q THEN
    send:=TRUE;             // Publish auslösen
END_IF

// ab hier jetzt eigenes publish
publish(
    Topic:= ADR(MyTopicSend),    // MyTopicSend ist definiert in TopicsBase !!
    PayloadString:= ADR(TextSend), 
    PublishAsString:= TRUE, 
    QoSIn:=SD_MQTT.QoS.ExactlyOnce,
    MRetain:= RetainMqtt, 
    send:= Send, 
    done=> SendDone,
    sendActive=>SendActive);

FL_Timeout(CLK:=publish.SendTimeout);
IF FL_Timeout.Q THEN
    A1_TextLogging(log_text:=concat(' TIMEOUT Broker ',BYTE_TO_STRING(Broker_Nr)));
END_IF
ERROR_TIMEOUT:=FL_Timeout.Q;

IF SendDone THEN    // Publish fertig
    send:=FALSE;
END_IF

Daruas deklariere ich 3 Instanzen:

Text_B1: M_c_MQTT_PublishRecieve;   // Hier sind pro Broker eine Instanz für das Senden und Empfangen deklariert.
Text_B2: M_c_MQTT_PublishRecieve;   
Text_B3: M_c_MQTT_PublishRecieve;

... und die reine MQTT-Funktion ist gegeben. Nur das das File "Application.ret" nun nicht mehr geschrieben wird beim Stoppen von codesys.

Irgendwie verstehe ich die Callback-Funktionen nicht. Ich müsste mal von Dir das Aufruf-Procedere, die Reihenfolge der durchlaufenen Funktionen erfahren. Dann könnte ich das leichter in eine Variante mit den 3 Brokern umstricken.

Viel Grüße Thomas

Tommilein commented 5 years ago

Hallo Stefan,

es wird immer enger... In dem anderen "issue" gab es mal beim Einführen von mehreren Brokern folgenden Hinweis:

Wie hast du die Broker getrennt? 
Ich würde dir pro Broker einen Client FB und eine MQTT_IN_OUT Struktur sowie pro Variable ,
einen publish FB, eine und einen subscription FB empfehlen. 
Unter dem Subscription FB können natürlich mehrere Topics bearbeitet werden.

Den callback FB kannst du jedoch für alle Broker nutzen. Das passt soweit.

Nun stelle ich fest, das mehrere "Subscriber" tatsächlich zu dem Problem mit den persistenten Variablen führen. 2 oder 3 Clients gehen.

Nach Deinem Hinweis bräuchte ich ja nur einen Subscriber. Aber dann habe ich keine Ahnung wie ich die Broker(!!) auseinanderhalten soll. In den Subscribern finde ich nicht einen einzigen Hinweis auf die URL oder was ähnliches, was mir erlauben könnte den Broker herauszufiltern.

Viele Grüße Thomas

stefandreyer commented 5 years ago

Hallo Thomas,

du darfst die Init Sachen nur einmal starten, du machst das bei jedem Ereigniss!

Lösche hier: IF NOT MyInit OR SwitchTrigger.Q THEN

das: OR SwitchTrigger.Q

Dadurch das du die Instance immer wider an de collecter hängst wird der immer länger und irgendwann geht der Speicher aus. Da ich das leider noch nicht abfange kanns bei dir Krachen. Das Problem habe ich in der aktuellen Version bereits behoben.

Ich hab dir mal was mit der aktuellen Version und 3 Brokern zusammengeschrieben. Bei mir gehts. nur flux.io ist gerade nicht erreichbar. Ich würde einen FB mach der alle 3 Broker bahandelt.

Hat den Vorteil das man dann nur noch den FB erweiter muss falls noch n 4 Broker dazu kommt und somit das ganze System gleich glatt zieht.

Schau mal rein.

Grüße Stefan MultibrokerExample.zip

Tommilein commented 5 years ago

Hallo Stefan, war das eine Freude, als ich die Mailankündigung sah. Ich verzweifle nämlich bald. Auch Dein Programm macht (aus meiner Sicht) nicht ganz, was es soll. Ich habe es um eine Visu ergänzt und schicke es Dir noch mal zu. Da haben wir jetzt eine gemeinsame Basis.

Es gibt zwei Probleme:

Zum Empfang: egal welcher Broker etwas sendet, es landet auf allen Subscribern. MQTT_3_ Recieved_2

Jedes "PublishRecieved" was existiert, wird durchlaufen. Ich habe mal testweise versucht, irgendwie über die "Instanz" zu gehen, das funktioniert auch bloß nicht (kann wahrscheinlich gar nicht).

MQTT_3_ Recieved_1

Ich suche krampfhaft nach einer URL, denn auch subscribe muß doch wissen, wo das Telegramm herkommt. Ich finde jedenfalls nichts...

Zu den Persistenten Variablen: Auch bei Deinem Testprogramm schreib der Raspberry kein "Application.ret", wenn mit "codesyscontrol stop" Codesys beendet wird (was nach 2 Stunden automatisch passiert.

Wenn du einen Raspberry hast, könntest Du das auch feststellen, wenn nach dem Stop von Codesys kein File
/var/opt/codesys/PlcLogic/Application/Application.ret geschrieben wird. Nach meinen ellenlangen Tests komme ich zu der Auffassung, daß das immer auftritt, wenn im Programm irgendwas mit "subscribe" definiert ist. Kommentiert man diebezüglich alles aus, funktionieren die persistenen Variablen - nur man kann nichts empfangen.

Das ist ein Raspberry, auf dem eine "echte" Anwendung läuft, die Deine 1. Version von MQTT (ohne callback) verwendet: MQTT_3_persist_1

Und das ist der Raspberry, auf dem ich gerade Dein Programm getestet habe. MQTT_3_persist_2

Falls Du das testen willst, nicht nur das Programm neu laden, sondern codesys neu starten, oder eben shutwon -r now. Da sollten die Daten auch erhalten bleiben.

Jetzt bin ich wieder bissel deprimiert - nix von diesen Problemen liegt in meiner Hand.

Viele Grüße Thomas

My_Multibroker_MQTT3_A.zip

stefandreyer commented 5 years ago

Hallo Thomas,

Danke für deinen Bemühungen! Habe essentiellen Fehler gefunden der immer beim abschalten der Applikation gegriffen hat und einen sauberen Shutdown verhindert hat, somit keine retains.

Im Angehangenen Projekt ist das korrigiert und funktioniert wieder.

Ich habe zusätzlich in den TextToBrokers weitere Strings eingefügt die nun von den einzelnen Brokern empfangen. Das kannst du schön beobachten wenn du an einen einzelnen Broker was per MQTT.FX and Topic:

TestTopicMultiBroker

sendest.

Du musst dir das so vorstellen: Wenn ein Client von einem Broker ein publish bekommt ruft er die im angegeben callback auf. das kann auch ein collector sein der mehrere instancen enthält. deswegen habe ich 3 collectoren für die 3 broker. somit werden für jeden broker die collectoren aufgerufen und an die instancen weitergegenen.

Ich hoffe wir kommen nun auf die Zielgerade.

Grüße Stefan My_Multibroker_MQTT3_A.zip

Tommilein commented 5 years ago

Hallo Stefan, Ich sehe das Ziel kurz vor mir - wenn Du nicht die Geduld mit mir verlierst...

Ich habe das Programm getestet und erst mal im Großen und Ganzen die Funktion erhalten , die ich mir vorstelle ( der Broker mqtt.fluux.io konnte bei Dir nicht gegangen sein - war nur ein "u" im "fluux". Mit 2 "u" ging er sofort).

Aber... Der Broker iot.eclipse.org will nicht so richtig. Das würde ich so unter "die öffentlichen testbroker gehen ja nie so durchgehend...", wenn nicht parallel meine "echte" Anwendung mit Deiner MQTT-Library Var. (ohne callback) einfach mit diesem Broker funktioniert.

Gesendet wird wohl richtig, denn mit mqtt.fx kann ich die gesendeten Telegramme nachweisen.

MQTT_4_empfang_1

Nur erkennt man sofort, das zwischen den gesendeten und den empfangenen Telegrammen eine Reihe Telegramme nicht ankamen. Zum Test habe ich mal "heisse" Topics benutzt und den Vergleich mit meiner "echten" Anwendung hergestellt. Deine erste Library kommt mit dem iot.eclipse.org hervorragend zurecht.

MQTT_4_empfang_2

Das Dumme ist nur, dass es Phasen gibt, da funktioniert alles und dann wieder mal schlecht. iot.eclipse.org ist auf jeden Fall sehr langsam. Da dauert es u.U. mehrere Sekunden, bis eine Antwort kommt. Gibt es einen Timeout, der vielleicht zu kurz für den Broker ist ??

Da es aktuell gerade mal wieder funktioniert, kannst Du nichts tun. Ich kann es nur beobachten.

Ich hänge das erweiterte Programm mal ran, vielleicht findest Du auch gleich wieder was , was ich verzapft habe.

Vielen Dank für Deine Mühen Grüße Thomas My_Multibroker_MQTT4_B.zip

primsam commented 5 years ago

Hallo,

Hier ist ja zur Zeit richtig was los :-) Passt hier zwar nicht so ganz rein leider ... ich bin mal so frech Und erstmal Danke an Stefan für die Super Arbeit^^ Bei mir hat bis jetzt eigentlich immer alles tadellos funktioniert ich habe das hier aber trotzdem sehr interessiert mitverfolgt und heute mal eine etwas aktuellere Version der lib getestet XD. Da ging dann klarerweise erstmal gar nix mehr ^^ Ich hab dann etwas an der lib bebastelt und ein paar typos entdeckt die unter Umständen Probleme machen können . Da ich schon dabei war hab ich dann das GreatExampleOfAdvantages auch angepasst und das sollte mit der Aktuellen lib so wieder laufen.

Grüsse Samuel Librarys_26_07_19.zip

stefandreyer commented 5 years ago

Hallo Samuel,

danke für deine Arbeit.

ich schaus mir mal über den Umweg mit den XMLs an.

Grüße Stefan

stefandreyer commented 5 years ago

Hallo Thomas,

eclipse spinnt bei mir auch, muss dem mal nachgehen obs an der lib oder dem broker leigt. Scheint aber auf jeden fall was zu blockieren...

Grüße Stefan

stefandreyer commented 5 years ago

Hallo Thomas,

scheint jetzt zu klappen.

Scheinbar hat mein clientWrapper ein Problem bei mehreren instancen, weiß aber noch nicht warum. Vielleicht lösche ihn einfach.

Versuch das mal:

My_Multibroker_MQTT4_B.zip

Grüße Stefan

Tommilein commented 5 years ago

Hallo Stefan, vielen Dank für Deine Arbeit. Ich schaue die Timestamps Deiner Project-Files nur noch mit Bewunderung an. Der iot.eclipse.org scheint die Verzögerung vielleicht selbst zu produzieren (Durchsatz begrenzen o.ä.), denn auch mit 2 mqtt.fx - Programmen geht es nicht schneller hin und her. Ist schon komisch. Lassen wir es mal eine Weile so stehen - vielleicht kan man damit leben.

Ich habe aber noch eine Bitte: Ich habe ja mit diesem Code:

gvl_Empfang_2:=ReceiveStringBroker2;
gvl_Empfang_3:=ReceiveStringBroker3;

IF gvl_Empfang_1 <> gvl_Empfang_temp1 THEN
    time_get_1:=sIstzeit_hh_mi_ss;
    gvl_Empfang_temp1:=gvl_Empfang_1;
END_IF
IF gvl_Empfang_2 <> gvl_Empfang_temp2 THEN
    time_get_2:=sIstzeit_hh_mi_ss;
    gvl_Empfang_temp2:=gvl_Empfang_2;
END_IF
IF gvl_Empfang_3 <> gvl_Empfang_temp3 THEN
    time_get_3:=sIstzeit_hh_mi_ss;
    gvl_Empfang_temp3:=gvl_Empfang_3;
END_IF  

ermittelt, wann ein telegramm ankommt. Ich finde das aber weiß Gott nicht schön, denn damit gehe ich über den Telegramminhalt, um zu erfahren, wann denn ein Telegramm eingegangen ist ( z.B. um den Eingangstimestamp zu bilden). Nun habe ich vom mqtt.fx mal einfach etwas gepublisht und immer wieder nur auf "publish" gecklickt. Und siehe da - nix wird erkannt, denn mit besagtem Code erkenne ich kein zweites identisches Telegramm.

Nun wollte ich in "TextToBrokers" ein Flag "recieved" produzieren und als EIN Rückgabewert aus den Instanzen von TextToBrokers ausgeben Ich habe nun gedacht, da die 3 Broker über Instanzen von "TextToBrokers" angesprochen werden, das ich aus "TextToBrokers" auch allgemeine Rückgabewerte zum aufrufenden Main-programm senden kann und klar ist von welchem Borker das kommt.

in TextToBrokers:

IF ReceiveStringBroker1<>'' THEN
    Empfangs_String:=ReceiveStringBroker1;
    ReceiveStringBroker1:='';
    recieved:=TRUE;                            // und das wird als "Ereignis" zurückgegeben 
ELSIF ReceiveStringBroker2<>'' THEN
    Empfangs_String:=ReceiveStringBroker2;
    ReceiveStringBroker2:='';
    recieved:=TRUE;
ELSIF ReceiveStringBroker3<>'' THEN
    Empfangs_String:=ReceiveStringBroker3;
    ReceiveStringBroker3:='';
    recieved:=TRUE;
ELSE
    recieved:=FALSE;
END_IF

Aber da verzweifle ich. Da kommen die gleichen Werte in allen Instanzen zur gleichen Zeit (im ersten Zyklus) zurück.

MQTT_5_Instanz_1

Wie kommt denn sowas ? Ich war ja schon verwundert, dass Du 3 Vars "ReceiveStringBroker1"..3 definiert hast. Wie muss ich denn da das Thema "Instanz" betrachten? Hintergrund: ich möchte nicht so oft an mehreren Stellen die Anzahl der Broker berücksichtigen müssen. Z.Z. ist ja jede Abfrage, jedes Flag u.ä so oft zu definieren, wie die Anzahl Broker. Bei den Clients sehe ich das ein, so "Grunddefinitionen" wie CLient_x, SubscriptionX, und noch ein PublishX müssen sein. Aber sonst müsste doch alles via Instanz nur einmal vorhanden sein. Oder liege ich da total falsch (wird ja so sein...)

Viele Grüße Thomas

stefandreyer commented 5 years ago

Hallo Thomas,

schau dir mal den TextToBroker FB an, der müsste alles machen was du brauchst. Der speichert die Zeit des letzten empfangs und gibt eine Flanke aus das was empfangen wurde. Den kannst du separat pro broker und subscription einsetzte, ohne eine broker Nummer an zu geben.

Grüße Stefan My_Multibroker_MQTT4_B.zip

Tommilein commented 5 years ago

Hallo Stefan, Ja, das ist genau das, was ich brauche, nur funktionierts noch nicht ganz. Der Broker mit der Nummer "1" (Client_1, Subscription1) liefert immer für alle Broker received := CallBackForStringBroker.received; =TRUE Ich nehme an, das da aus Versehen noch was für den Client_1 hart codiert rumliegt.

MQTT_3007_3fach_empfang_A

Die anderen beiden Broker funktionieren, es liegt auch nicht an einem bestimmten Broker, ich habe sie in der Reihenfolge ausgewechselt: MQTT_3007_3fach_empfang_B

Dann habe ich einen 4. Broker eingebaut, aber als Client_0 usw. Und siehe da, dieser funktioniert und weiterhin Client_1 (obwohl nicht mehr an erster Stelle) schlägt für alle wieder zu: MQTT_3007_3fach_empfang_D

MQTT_3007_3fach_empfang_E

Ich kann den Fehler wohl nicht finden, weil ich nicht in die Lib so weit reinschauen kann. Ich finde jedenfalls keinen Zugang. Ich würde Dir ja gern gleich die Lösung präsentieren. Kann ich aber nicht.

Der Broker 4 "broker.hivemq.com" funktioniert zusammen mit "broker.mqtt-dashboard.com:1883" nicht richtig. Sie sind wohl ein und derselbe Broker (aufeinander verlinkt), deshalb habe ich den letzten Client auf FALSE enabled (dasselbe trifft auf iot.eclipse.org umd m2m.eclipse.org zu). Einzeln laufen sie alle beide. Ich finde aber keinen 4. freien Broker - "test.mosquitto.org" ist wieder mal nicht zu erreichen.

Aber es liegt auch nicht an einem weiteren Broker - der würde schon funktionieren, sondern nur an Broker 1 (!).

Im angehängten programm sind 4 Clients drin und der 2. Client ist CLIENT_1, der sich so anstellt. My_Multibroker_MQTT_3007.zip

Viele Grüße Thomas

SOOO... kurz bevor ich "Comment" drücken wollte hat mein Ego es noch mal versucht beim Durchschauen des Programms: und ich habe es gefunden (in TextToBroker):

    MyInit := TRUE;
    CallBackForStringBroker.Init(topic:= ADR(DummyTopic), payload:= ADR(ReceiveStringBroker));
    //Main.clients.Collector1.put(instance:= CallBackForStringBroker);

END_IF

Das musste erst raus: Main.clients.Collector1.put(instance:= CallBackForStringBroker);

Ich lasse das Ganze mal hier drin, um darzustellen, wie schwierig manchmal das Suchen ist. Im angehängten Programm ist's noch drin...

Ich hoffe, das war's ....

stefandreyer commented 5 years ago

Hallo Thomas,

ich habe das nicht auf Herz und Nieren geprüft bevor ich es veröffentlicht habe. Aber du hast den Fehler gefunden .... Prima....

Viel Erfolg

Grüße Stefan

Tommilein commented 5 years ago

Hallo Stefan, ich teste und teste, dann hauen mir abhanden gekommene Broker die Füße weg. "iot.eclipse.org" wurde in "mqtt.eclipse.org" umgewandelt. Aber da geht keine websocket-Verbindung mit Javascript. Also habe ich mich mal bei "broker.shiftr.io" angemeldet und habe dort versucht, Verbindungen aufzubauen. Das besondere ist, das ich dort mit username und password arbeiten muss, auch wenn ich nicht TLS nutze.

Sei es wie es sei: mit Javascript connected es, ich bekomme nur vom Codesys nichts zurück:

MQTT_shiftr_3

mqtt.fx geht auch:

MQTT_shiftr_2

aber mein Raspberry mit Codesys will nicht connecten:

Ich glaube "Protokoll" und "Path" sollten auch was abbekommen an Daten. Aber wie gebe ich das vor - oder muss es gar nicht sein (bei 'broker.mqtt-dashboard.com' sind die Felder genauso).

Client3(
    MQTT_IN_OUT:= GVL_MQTT.MQTT_IN_OUT_BROKER3, 
    ENABLE:= TRUE, 
    //URL: use format: user:password@domain:port
    URL:='userbname:pwd@broker.shiftr.io:1883',
    TIMEOUT:= T#10S, 
    TLS:= FALSE);

Ich lasse mal das pwd offen, dann kannst Du den Zugang zum Testen nutzen. Kann ich später wieder ändern.

Vielen Dank Thomas

stefandreyer commented 5 years ago

Hallo Thomas,

Fehler gefunden,

versuch mal die Version:

MQTT.zip

Grüße

Tommilein commented 5 years ago

Hallo Stefan,

Du bist ein Held ... Bibliothek eingespielt und es funktioniert. MQTT_shiftr_4

Damit habe ich eine bedeutend größere Zahl von möglichen Brokern. Die typischen Broker wie mqtt.eclipse.org (iot.eclipse.org wurde einfach dahin umbenannt) stehen entweder nie lange zur Verfügung oder verlieren ihre Websocket-Fähigkeit oder, oder... Gut, sind ja nur zum Testen da. Aber das macht man etwas zu eifrig für meinen Geschmack.

Jetzt kann ich mit username/passwd etwas (wahrscheinlich) stabilere Broker angehen. Vielleicht versuche ich mal Amazon...

Danke für Deine Arbeit. Viele Grüße Thomas

Tommilein commented 5 years ago

Hallo Stefan,

ich habe mich zu früh gefreut. Der Broker mit username geht wohl, aber ein alter Fehler ist wieder aufgetaucht: Die persistenten Variablen verschwinden nach Neustart ... bzw. werden beim Stop nicht abgespeichert.

Es gibt wieder kein "Application.ret":

root@rasp_1:~# ls -l /var/opt/codesys/PlcLogic/Application
insgesamt 5016
-rw-r--r-- 1 root root 5130256 Aug 19 13:06 Application.app
-rw-r--r-- 1 root root      20 Aug 19 13:06 Application.crc
root@rasp_1:~#

Das hatten wir schon mal... Hast vielleicht eine veraltete Version geändert ??

Viele Grüße Thomas

Ergänzung: ich kann auch kein Programm laden, ohne vorher alle Files aus /var/opt/codesys/PlcLogic/Application rauszulöschen ...

stefandreyer commented 5 years ago

Probier mal ein Reset Kalt, ob da ein Runtime error hochkommt.

Grüße

Tommilein commented 5 years ago

Hallo, beim Kaltstart wird ein Application.ret geschrieben. Beim Codesys-restart nicht.

.... ob da ein Runtime error hochkommt.

Da habe ich wieder nicht viel Ahnung. Das ist passiert bei Kaltstart:

MQTT_reset_kalt

Ich denke aber, das ist normal.

Im Device unter "Log" kam aus meiner Sicht kein Fehler. MQTT_reset_kalt_2

-

-

Wenn ich aber ein normales download veranlasse, z.B. nach Programmänderung, dann geht fast nichts mehr.

MQTT_reset_kalt_3

Irgendwie wird das ganze Directory /var/opt/codesys/PlcLogic/Application gelöscht, was ja wohl nicht sein sollte, denn Application.ret hält ja die persist. Vars.

Weiss nicht, ob das hilft...

Grüße Thomas

Tommilein commented 5 years ago

Hallo Stefan, noch eine Ergänzung: ich habe mal nach oben geschaut und da gibt es von Dir den Eintrag:

Hallo Thomas,

Danke für deinen Bemühungen! Habe essentiellen Fehler gefunden der immer beim 
abschalten der Applikation gegriffen hat und einen sauberen Shutdown verhindert hat, 
somit keine retains.
Im angehangenen Projekt ist das korrigiert und funktioniert wieder.

Das aktuelle Problem sieht in sich meinen Augen als das gleiche an.

Grüße

stefandreyer commented 5 years ago

Hallo Thomas,

Online gehen, dann Online --> Reset Kalt, dann sagt er dir was für ein Fehler.

Grüße

Tommilein commented 5 years ago

Hallo Stefan, habe ich ja schon gemacht. Aber hier nochmal durchgeführt:

MQTT_reset_kalt_5

Ausser der Ausschrift "Programm geladen - Ausnahmefehler" kann ich nichts erkennen. Auch im LOG ist nichts zu finden.

Bei einem 2. Kaltstart-Versuch kamen im LOG diese 2 Zeilen: MQTT_reset_kalt_7

"Access Violation" deutet ja auf einen Zugriffsfehler hin. Komisch nur: bei Kaltstart wird immer ein "Application.ret" geschrieben und nach dem Kaltstart sind die persist. Vars erhalten geblieben. Bei einem Codesys-Stop/Start bleiben sie nicht da.

Könntest Du mir mal erklären, was Du vom "Kaltstart" erwartest ??

Viele Grüße Thomas

Tommilein commented 5 years ago

Hallo Stefan,

ich versuche mitzusuchen, nicht besonders erfolgreich - aber interessant. Ich habe ein Programm gefunden von einem freundlichen Franzosen oder Belgier ( weil französische Kommentare drin sind). Das speichert die Retain Vars in ein File. Nun habe ich gedacht, übernehme es in dein Programm, dann wird gesichert - egal was der Stefan so macht. In Klammern denkste. Ich kann fast das gleiche Verhalten feststellen wie beim normalen Codesys-Restart mit der letzten, aktuellen MQTT-Lib. Das ret-File wird beim Abfahren von Codesys gelöscht und kein neues geschrieben !!

Ich möchte meine Variante nicht unbedingt zum Standard erheben, da ich nicht weiß, ob ich das Speichern an der richtigen Stelle mache. Ich habe das Programm in das Systemereignis "StopDone" zum Save eingefügt und in "PrepareStart" das Restore des ret-Files (wenn denn eins da war).

Es kam, wie schon erwähnt, trotzdem zum Verlust der ganzen Retain Vars, weil kein File geschrieben wurde.
Das ist das Programm (der SAVE-teil):

PROGRAM Retain_Save_Restore
VAR_INPUT
    RESTORE: BOOL;
    SAVE: BOOL;
END_VAR

VAR
    fbDelete            : FILE.Delete; (* bloc pour effacer le contenu du fichiere *)
    //sFileName           : STRING := 'data.ret';
    sFileName           : STRING := '/var/opt/codesys/PlcLogic/Application/retain_data.ret';
    pApp                : POINTER TO APPLICATION;
    Result              : RTS_IEC_RESULT;
    xInit               : BOOL;
    comment:  STRING(80);
END_VAR

IF SAVE=TRUE THEN   
     (* En premier effacer le fichier.
          car la fonction AppStoreRetainsInFile ajoute les données à la suite du fichier. *)

    fbDelete(xExecute:=TRUE, sFileName:=sFileName);  
    IF fbDelete.xDone OR (fbDelete.xError AND fbDelete.eError = File.Error.NOT_EXIST) THEN  
             fbDelete(xExecute:=FALSE);
             SAVE := FALSE;  

             (* enregister. *)
             IF pApp <> 0 THEN
         Result := AppStoreRetainsInFile(pApp,sFileName);  //RETAINs in File schreiben   
             END_IF
        END_IF
END_IF

Zusammengefasst:

Wenn ich das ganze delete-Zeug rausnehme, dann funktioniert alles ( das ret-File wird sauber überschrieben), aber nur in einem fremden Directory, jedoch nicht dort wo die Application-Files liegen.

Bei diesen Tests mit "Fremdfiles" konnte ich feststellen, das beim "Download" das Application.ret-File auch gern mal hinten ran geschrieben wird ( funktionierte meist nur beim "download"), so daß es die doppelte Länge hat. -rw-r--r-- 1 root root 4891584 Aug 20 16:29 Application.ret

Normal ist das: -rw-r--r-- 1 root root 2445792 Aug 20 16:11 Application.ret

Da hat scheints niemand gemerkt, das mal nicht richtig gelöscht wurde.

Also muss irgendwas mit dem Baustein "FILE.Delete" sein. Vielleicht wird da irgendwas überschrieben, oder, oder, oder

Beim "mit Download einloggen" kommt es immer(!) zu Absturz, so daß ich versuche mit Online-Change auszukommen. Was schlecht beim Testen geht, wenn was im Init-Teil eines Programmes geändert wurde.

Ich hoffe jetzt wieder auf eine neue LIB, glaube ich doch noch fest an den Fehler von vor ein paar Wochen.

Viele Grüße Thomas

stefandreyer commented 5 years ago

Hallo Thomas,

zum Hintergrund: Wenn die Runtime aus irgend einem Grund gestoppt oder zurück gesetzt wird, werden ein Paar Funktionen zum bereinigen des Dynamischen Speichers aufgerufen. Dabei scheint es bei dir zu Krachen. Und wenn dann ein Ausnahmefahler auftritt werden die Retains nicht geschrieben.

Auf welchen System krachts bei dir? Beim Raspi?

Hab gerade nochmal das GreatExampleOfAdvanteges auf dem Raspi am Laufen und den Reset gemacht, keine Probleme.

Kannst du mir dein Projekt bereinigt zukommen lassen?

Grüße Stefan

stefandreyer commented 5 years ago

Hallo Thomas,

Problemstelle gefunden... Ich bleibe dran....

Grüße

Tommilein commented 5 years ago

Hallo Stefan, freut mich zu hören, das Du was erkennen kannst. Ich habe heute schon mal sowas gesehen:

MQTT_retain_3

Das ist mir passiert bei meinen Übungen beim "eigenentwickelten" Speichern der Retain-Vars. Das läuft doch genau in die Richtung ??

Mein Project habe ich beim Wechsel der letzten Lib nicht verändert.

Grüße Thomas

stefandreyer commented 5 years ago

Versuch das mal...

MQTT.zip

Tommilein commented 5 years ago

geht sofort los ...

Tommilein commented 5 years ago

Aaaaalsooo, ich traue mir nicht mehr "Heureka" zu brüllen. Ganz still und leise würde ich sagen, das die LIB jetzt so gehen sollte. Jedenfalls ist die "Application.ret" wieder da. So nebenbei glaube ich sogar ein schnelleres MQTT-Verhalten zu erkennen - ist aber vielleicht nur Einbildung. Und ein Login mit "download" geht auch normal durch.

Ich bin Dir dankbar, daß Du die Nerven ob meiner Bockigkeit nicht verloren hast. Aber was soll ich denn ohne Dein zutun auch machen ??

Vielen Dank (für heute...). Ich hoffe, daß es das wieder mal war. Bis ich wieder in den nächsten von normalen Menschen nie benutzten Programmwinkel krieche.

Viele Grüße Thomas

stefandreyer commented 5 years ago

Hallo Thomas,

ist doch super wenn einer einen Implementierungstest macht....

So werden Fehler gefunden.

Schneller kann eigentlich nicht sein.

Grüße Stefan