e!Cockpit MQTT FbSubscribeMQTT

WAGO Soluteer

Member
Beiträge
22
Punkte Reaktionen
0
Ich würde eine Struktur bauen und die in ein Array schmeißen mit einem Zeiger auf das letzte Element. So kann man die Elemente nacheinander abarbeiten (der FB braucht zum Senden mehrere Zyklen!)

STRUCT typMsg sTopic: STRING; sMessage: STRING; END_STRUCT STRUCT typBuffer iPosition: INT; aMsg: ARRAY[1..MAX_MSG] OF typMsg; END_STRUCT myBuffer: typBuffer;
Dann deklarierst du den Puffer als Variable und schreibst deine Nachrichten an die Stelle "iPosition+1" wenn iPosition<MAX_MSG.
Dann muss nur der FbPublisher die Nachrichten wegsenden, wenn xTrigger=FALSE und iPosition>0 ist. Je nachdem wie die Nachrichten rausgehen sollen, musst du das korrekte Element übergeben. myBuffer.aMsg[1] wär ein FIFO und myBuffer.aMsg[iPosition] ein FILO. Beim FIFO müssen alle nachfolgenden Elemente hochkopiert und der Positionszeiger um 1 verringert werden. Beim FILO wird einfach nur iPosition um 1 verringert ohne umzukopieren.
 
OP
J

Jproject

Active member
Beiträge
40
Punkte Reaktionen
4
Zuviel Werbung?
->Hier kostenlos registrieren
Das anlegen der STRUCT typMsg und typBuffer klingt erstmal plausibel.
Jetzt habe ich nicht ganz verstanden, wie du die Daten einschreiben willst.
Ich hatte jetzt folgende Ansatz aber ich bin mir nicht sicher ob ich richtig liege:

Code:
PROGRAM Test
VAR
        //Publish Test
    oFbPublish: WagoAppCloud.FbPublishMQTT_2 (eConnection:= 1);
    xMyTrigger        : BOOL := FALSE;
    dwBusyCounter    : DWORD := 0;
    dwErrorCounter    : DWORD := 0;
    dwBytesCount     : DWORD;
    xTaster1: BOOL;
    xTest: BOOL;
    sTopictoPublish: STRING(255):= '';
    aBufferData: POINTER TO BYTE;
    sMessage: STRING;
    BufferData: typBuffer;
    ptSource: POINTER TO BYTE; // Quellpointer
    ptDestination: POINTER TO BYTE; // Zielpointer
END_VAR

// Trigger MQTT publish
oFbPublish(sTopic := ,
            eQualityOfService := 1,
            dwSize := dwBytesCount,
            aData := ,
            xTrigger := xMyTrigger);

FOR BufferData.iPosition :=1 TO 100 DO
       
        IF BufferData.iPosition >100 THEN
            BufferData.iPosition:= 1;
           
        ELSIF BufferData.iPosition <100 AND oFbPublish.xTrigger = FALSE THEN

                ptSource:=ADR(sMessage);
                ptDestination:=ADR(aDaten);  

                oFbPublish.xTrigger := TRUE;
        END_IF
       
       
END_FOR

Ich weiß halt nur nicht, wie ich mein Topic und meine Message in das Array aMsg schreiben soll und vor allen wie ich die Daten dann abrufe und in den FbPuplish übergebe?
 

WAGO Soluteer

Member
Beiträge
22
Punkte Reaktionen
0
Ich habe es befürchtet :confused:
Zuerst einmal kannst du den Puffer nicht mit einer FOR-Schleife aufrufen, das ist Unsinn.
Dann musst du dein Sendedaten ja irgendwie in den Puffer reinschreiben. Dazu ist dann "iPosition", welches den "Füllstand" des Puffers anzeigt. Also z.B. Rückmeldung Licht "90%" -> Nachricht in Puffer schreiben. (würde ich über einen separaten FB lösen, der die Nachricht in den Puffer einträgt) Dann füllt sich der Puffer mit Nachrichten und du musst die mit dem FbPublish wegschicken. Das tust du, wenn:
1. xTrigger FALSE ist
2. iPosition>0
Wenn diese Voraussetzungen erfüllt sind, lädst du die gewünschte Nachricht (wir sprachen von "sTopic" und "sMessage" des zu sendenden Elementes, z.B. [1]) auf den FbPublish und setzt den Trigger auf TRUE.
Ist das Senden abgeschlossen (Trigger wird selbstständig zurückgesetzt) solltest du das gesendete Element löschen; in meinem Beispiel dann via FOR-Schleife alle folgenden Elemente hochkopieren und iPosition um 1 verringern.
Dann beginnt das gleiche Spiel von vorn. Ist eigentlich nicht schwer...
 

Blockmove

Supermoderator und User des Jahres 2019
Teammitglied
Beiträge
8.935
Punkte Reaktionen
2.301
Jetzt misch ich mich auch mal ein:
Bedingung für Publish ist ja im Prinzip ein auslösendes Event.
Je nach Verarbeitung auf dem anderem System (Visualisierung, Leitsystem) kann auf der SPS eine Queue sinnvoll sein.
Sowas macht man normalerweise mit einem FIFO.
 

WAGO Soluteer

Member
Beiträge
22
Punkte Reaktionen
0
Zuviel Werbung?
->Hier kostenlos registrieren
Jetzt misch ich mich auch mal ein:
Bedingung für Publish ist ja im Prinzip ein auslösendes Event.
Je nach Verarbeitung auf dem anderem System (Visualisierung, Leitsystem) kann auf der SPS eine Queue sinnvoll sein.
Sowas macht man normalerweise mit einem FIFO.
Das steht ja schon in den vergangenen Posts und bringt den Kollegen hier nicht weiter.
 
OP
J

Jproject

Active member
Beiträge
40
Punkte Reaktionen
4
Ich habe jetzt Folgendes getan einen Aktionsbaustein angelegt, um die Werte erst mal in das Array zu bringen:

Code:
    BufferData.aMsg[1].sMessage := TO_STRING (GVL.rWohnzimmer_Licht_Haenge_Value);
    BufferData.aMsg[1].sTopic := '1.Etage/Wohnzimmer/Licht1/state';
   
    BufferData.aMsg[2].sMessage := TO_STRING (GVL.rWohnzimmer_Licht_Spots_Value);
    BufferData.aMsg[2].sTopic := '1.Etage/Wohnzimmer/Licht2/state';
   
    BufferData.aMsg[3].sMessage :=TO_STRING( GVL.rKizi1_Licht_Value);
    BufferData.aMsg[3].sTopic := '1.Etage/Kinderzimmer1/Licht1/state';
   
    BufferData.aMsg[4].sMessage :=TO_STRING( GVL.rKizi2_Licht_Value);
    BufferData.aMsg[4].sTopic := '1.Etage/Kinderzimmer2/Licht1/state';
   
    BufferData.aMsg[5].sMessage :=TO_STRING( GVL.rFlur_Licht_Value);
    BufferData.aMsg[5].sTopic := '1.Etage/Flur/Licht1/state';
   
    BufferData.aMsg[6].sMessage :=TO_STRING( GVL.rKueche_Licht_Value);
    BufferData.aMsg[6].sTopic := '1.Etage/Küche/Licht1/state';
   
    BufferData.aMsg[7].sMessage :=TO_STRING( GVL.rklFlur_Licht_Value);
    BufferData.aMsg[7].sTopic := '1.Etage/kleinerFlur/Licht1/state';
   
    BufferData.aMsg[8].sMessage :=TO_STRING( GVL.rBad_Licht_Value);
    BufferData.aMsg[8].sTopic := '1.Etage/Bad/Licht1/state';

Ich hoffe das ist erstmal soweit i.O.
 

WAGO Soluteer

Member
Beiträge
22
Punkte Reaktionen
0
Wenn ich deinen Code sehe, möchtest du die Werte immer senden. Ich war davon ausgegangenen, dass du die Nachrichten/Werte dynamisch senden willst... Soll die Steuerung ständig senden oder nur bei "Bedarf" (Wertänderung, 1x pro Minute o.Ä.)? Das ändert nämlich deinen Code.
 
OP
J

Jproject

Active member
Beiträge
40
Punkte Reaktionen
4
Also ich würde die Werte gerne alle 500 ms - 1s die Werte verschicken.
Natürlich kann man auch nur nach Wertänderungen senden, das würde die Netzwerklast etwas herunter setzten.
 

Blockmove

Supermoderator und User des Jahres 2019
Teammitglied
Beiträge
8.935
Punkte Reaktionen
2.301

WAGO Soluteer

Member
Beiträge
22
Punkte Reaktionen
0
Zuviel Werbung?
->Hier kostenlos registrieren
Dann würde ich dir pro Nachrichtenquelle einen FbPublisher empfehlen. Ich dachte, es geht um "BYTE-Sparen" und nicht um die größte Performance...
Noch eine andere Idee: Wenn ich die Beschreibung von openHAB richtig lese, kannst du auch Modbus TCP verwenden. Das wäre für deine Anforderung des schnellen Datentransfers eher geeignet.
 
OP
J

Jproject

Active member
Beiträge
40
Punkte Reaktionen
4
Modbus als Übertragungsprotokoll hatte ich auch schon im Einsatz. Problem bei obenHAB ist aber die Verarbeitung der Empfangen Modbus-Daten. Diese müssen immer umgewandelt werden beim Empfangen und senden. Zusätzlich muss man in dann noch viel mehr Variablen anlegen.

Meine Vorstellung ist, die aktuellen werde in das Array der Struktur abzulegen und diese dann nach und nach über einen FbPublish zu versenden.
 

WAGO Soluteer

Member
Beiträge
22
Punkte Reaktionen
0
Das kannst du machen; musst aber bedenken, dass bei der Benutzung von einem Baustein die Latenzzeiten größer werden, d.h. je mehr du Nachrichten über einen FB schickst, desto länger dauert es, bis die erste Quelle wieder gesendet wird. Das kannst du nur umgehen, indem du mehr Instanzen des FB definierst. Ich würde jeder Quelle einen FB spendieren.
Außerdem kannst du noch die Nachrichtengröße unter den Globalen Parametern im Librarymanager anpassen. Ich glaube das Payload ist da standardmäßig (zu) hoch eingestellt.
 
Oben