UDP Read JSON

Hallo,

ich habe einen Drucker der per UDP / JSON-Request aktuelle Stati zurückliefert.

Doku:

Interessieren würde mich, wie ich z.B. einen {„read“:„global_counter“} absetze und das Ergebnis zu Symcon zurück bekomme.
(Leider konnte mir der Hersteller da nicht weiter helfen und ich selbst habe da keinen Plan…)

Einen UDP-Socket zum Drucker habe ich erstellt, aber wie sende ich da?
In der Symcon-Doku fand ich nur „boolean USCK_SendText (integer $InstanzID, string $Text)“ aber damit bekomme ich ja keine Werte zurück geliefert…

Oder gibt es hier im Forum was, an dem ich mich orientieren könnte?

Öffne mal den Debug des Sockets (rechts oben der Käfer) in der offenen Instanzkonfiguration.
Dann setze per Script deinen USCK_SendText ab und schaue ob eine Antwort kommt.

Falls ja, ein Script „Drucker auswerten“ anlegen sowie eine Instanz „Register Variable“ anlegen. Die Variable erhält als Gateway den UDP Client Socket und als Ziel das Script. Weitere Infos in der IPS Doku zu Register Variable.

Hallo Jürgen,

Die Verbindung ist eine TCP/IP. Deswegen lege mal einen Clientsocket in Symcon an. Standard Port bei Auslieferung des Druckers ist 34568. Dann den o.g. JSON String senden und der m610 Antwortet darauf.

Danke für die schnellen Antworten.
Die Firewall-Config zwischen Symcon und dem Drucker dauerte etwas…
(Auf UDP kam ich wegen dem JSON Commander mit welchem ich teste.)

So weit bin ich:
$Text=„read:global_counter“;
CSCK_SendText (48840, $Text);

08.12.2020, 16:07:41 | TRANSMIT | 72 65 61 64 3A 67 6C 6F 62 61 6C 5F 63 6F 75 6E 74 65 72

Nun frage ich mich:

  1. [li]Eigentlich müsste ich den Text wohl als „{„read“:„global_counter“}“ schicken. [/li]Aber wie bekomme ich das mit den Sonderzeichen in eine Variable?
    Ein Escape-Versuch mit „{„read:global_counter“}“ liefert zumindest keinen PHP-Fehler, aber natürlich einen anderen Transmit:
    08.12.2020, 17:46:47 | TRANSMIT | 5C 7B 22 72 65 61 64 3A 67 6C 6F 62 61 6C 5F 63 6F 75 6E 74 65 72 22 5C 7D
    [li]Auf den Transmit „read:global_counter“ kam irgend wie keine Antwort, da ist ja nur der Transmit… [/li]Mit welchem Befehl schickt man denn den Read?
    Wie bekomme ich die Antwort in ein Array?
    CSCK_SendText liefert ja nur true oder false zurück.
    „string ReceiveData (string $JSONString)“ habe ich da gefunden, könnte das klappen? Wie in php einbauen?

Erstmal muss im Debug eine Antwort sichtbar sein. Dann kann man sich darum kümmern den Auszuwerten.
Dafür gibt es die RegisterVariable. Einfach mal dazu in die Doku gucken.

Zum Thema Sonderzeichen in Variable. Das einfachste ist ’ statt " zu verwenden. Also etwa so
$text = ‚{„blub“}‘;

Ggf. musst du auch noch ein
oder \r nachsenden. Dsa ginge dann etwa so:
$text = ‚{„blub“}‘ . "
";

beachte hier die unterschiedlichen Anführungszeichen, wodurch in den " aus dem
tatsächlich der passende Ascii Code wird.

Hi,

Ja das sollte funktionieren:

$text = '{"read":"global_counter"}';

Ich bin morgen in der Firma, da müsste noch so ein Drucker rumliegen. Den nehm ich mal mit, dann kann ich das testen.

So hatte ich das mal für Siemens TIA per TCP auf Port 34568 gemacht:
TIA4.png

Attain

Hurra, es klappt.
Danke für eure Tips !!!

Damit es Anfänger wie ich evtl. später mal leichter haben, hier mein Versuch einer „Anfänger-Doku“.

Q: Warum gab es vom Drucker keine Antwort?
A: Die Firewall hatte die noch blockiert.

Q: Welchen String sende ich jetzt?
A: $Text = ‚{„read“:„global_counter“}‘;
CSCK_SendText (48840<-Client-Socket-ID, $Text);

Q: Wie werden die Werte ausgelesen?
A: Der Register-Variablen Tip hat mir geholfen. Die Doku von Symcon dazu ist für mich als Anfänger nicht sonderlich hilfreich, ich hatte das aber schon mal geschafft und nun konnte von meinem alten Script abschauen…

Meine Schritte (für Anfänger):

  1. Client Socket anlegen:
    Rechte Maustaste -> Objekt hinzufügen -> INSTANZ auswählen, nach „Client“ suchen und einen Client-Socket anlegen.
    Diesen dann mit IP und Port konfigurieren und aktivieren.

  2. Script für das Absenden der Anfrage anlegen.

$Text = '{"read":"global_counter"}';
CSCK_SendText (48840<-- ID des ClientSocket aus (1.), $Text);
  1. Script für das verarbeiten des Ergebnisses anlegen und folgenden Code rein kopieren:
    Beispiel-Code:

// wenn das Skript von einer RegisterVariable-Instanz aus aufgerufen worden ist
if ($_IPS['SENDER'] == "RegisterVariable") {
    $data = $_IPS['VALUE'];
    // Ausgabe in den Symcon-Meldungen zum debuggen
    // print_r("Socket Script wurde aufgerufen
");
    // print_r($data);
 
    // wenn das Trennzeichen "," in $data gefunden worden ist
    if (strpos($data, ',')) {
        // $data in durch "," separierte Datensätze zerlegen
        $datasets = explode(',', $data);
 
        // alle Datensätze ausgeben
        for ($i = 0; $i < count($datasets) - 1; $i++) {
            echo "empfangener Datensatz: ".$datasets[$i]."
";
        }
        // Stand in die Variable wegschreiben. 
        // Ich brauche nur den 1. Wert des Array.
        SetValueInteger(59640,$datasets[1]);

    }
}

  1. Register-Variable anlegen:
    Rechte Maustaste -> Objekt hinzufügen -> INSTANZ auswählen, nach „Register“ suchen und so eine Instanz und nicht eine „Variable“ anlegen…

  2. In die Instanz-Config der unter (4.) erzeugten „Register-Variablen“ rein gehen und zunächst mit „Gateway ändern“ den unter (1.) angelegten Client-Socket zuordnen. Dann noch das Script aus (3.) zuordnen und abspeichern.

  3. Script aus (2.) starten, dadurch wird der Abruf der Daten an den Drucker geschickt und die Antwort wird vom Script aus (3.) verarbeitet.

Kannst du uns mal die Antwort(en) des Druckers zeigen? Ich vermute ein json_decode hätte dir auch helfen können.

Mit


........
if ($_IPS['SENDER'] == "RegisterVariable") {
    $data = $_IPS['VALUE'];
    $instanz = $_IPS['INSTANCE'];

    // Ausgabe in den Symcon-Meldungen zum debuggen
    print_r("Socket Script W41 wurde aufgerufen
");
    print_r($data);
    print_r($instanz);
    print_r($_IPS['SENDER']);
    print_r($_IPS['CLIENTIP']);
.........

kommt bei den Meldungen

10.12.2020, 22:58:42 | Register Variable    | Socket Script W41 wurde aufgerufen
{
    "globalcounter": [
        2363554,
        2363464,
        2363374,
        2363329,
        0,
        0
    ]
}
28099

10.12.2020, 23:08:50 | TRANSMIT | 7B 22 72 65 61 64 22 3A 22 67 6C 6F 62 61 6C 5F 63 6F 75 6E 74 65 72 22 7D
10.12.2020, 23:08:50 | RECEIVED | 7B 0A 20 20 20 20 22 67 6C 6F 62 61 6C 63 6F 75 6E 74 65 72 22 3A 20 5B 0A 20 20 20 20 20 20 20 20 32 34 38 31 30 39 38 2C 0A 20 20 20 20 20 20 20 20 32 34 38 30 39 33 33 2C 0A 20 20 20 20 20 20 20 20 32 34 38 30 38 32 33 2C 0A 20 20 20 20 20 20 20 20 32 32 38 37 38 30 38 2C 0A 20 20 20 20 20 20 20 20 30 2C 0A 20 20 20 20 20 20 20 20 30 0A 20 20 20 20 5D 0A 7D 0A

$_IPS[‚SENDER‘] und $_IPS[‚CLIENTIP‘] bleiben leider leer.
Insgesamt frage ich die Stände von 8 Druckern mit je 4 von 6 bestückten Druckköpfen ab.
(Deshalb 42363xx und 20 in der Antwort.)

Das ganze jeweils nach Schicht-Ende, dann müssen die Jungs nicht immer Zahlen für ihre bisher von Hand gemachte Statistik sammeln. Morgends um 6 wird dann noch die Tagessumme der Linie berechnet.

$_IPS[‚INSTANCE‘] liefert wenigstens was (hier die 28099).
Damit mache ich dann beim auswerten die Zuordnung zu den Variablen.

     switch($instanz) {  

                case'51732': // UMA
                switch($jetzt){
                    case "06":
                        $neu=$datasets[1] - GetValueInteger(18891);
                        $tagessumme = $neu;
                        SetValueInteger(22008,$neu);
                        SetValueInteger(18891,$datasets[1]);
                        break;
                    case "14":
                        SetValueInteger(44182,$datasets[1]);
                        break;
                    case "22":
                        SetValueInteger(59640,$datasets[1]);
                        break;
                }


                case'22085': // UMB
                switch($jetzt){
                    case "06":
                        $neu=$datasets[1] - GetValueInteger(30780);
                        $tagessumme = $tagessumme + $neu;
                        SetValueInteger(55134,$neu);
       .........
.........

Wobei das „Sammel-Script“ mit dem Case noch nichts taugt.
Das „Switchen“ durch die Instanz-Nummern scheint nicht immer sauber zu klappen, das läuft wild durcheinander.

Auch das aufaddieren der Tagessumme klappt so natürlich nicht, da das Script ja nicht „von oben“ durchläuft, sondern auch mal in der Mitte startet, wenn ein Ergebnis von dem Drucker zuerst zurück kommt.
$neu wird dabei auch oft im Speicher verwürfelt und die Zahlen passen dann nicht.

Also wie man elegant die Rückmeldungen mehrerer Socket in einem Script erledigt habe ich noch nicht so richtig herausgefunden…

Hallo Attain,

ich bin neu hier und weiß nicht ob ich hier jetzt richtig schreibe in diesem Thema. Entschuldigt bitte wenn das falsch ist. Ich stehe gerade vor dem Problem im TIA die Wolke m610eom anzusprechen und weiß nicht wirklich wie ich das anstellen soll. Sowas habe ich noch nicht gemacht. Da du hier geschrieben hast, dass du das schon mal getan hast, würde ich dich fragen und bitten, ob du mir bißchen Hilfestellung geben könntest. Im Prinzip möchte ich ein variables Zählerfeld im Etikett vom Drucker lesen können und dann den Zähler immer neu vorgegeben vor jedem Druck. Die TCP Verbindung habe ich aufgebaut.

Hallo,
ich habe immer nur die Zähler ausgelesen und die Werte dann protokolliert.
Schlussendlich habe ich es in Python geschrieben und in eine MySQL gespeichert.

Das Senden von Werten an den Wolke müsste aber auch gehen, schau mal auf Seite 105ff. in dem PDF welches ich oben verlinkt habe.

#!/usr/bin/python

from sys import exit
#from time import *
import os
import time
#from funktionen import *
#import MySQLdb
#import mysql.connector
import pymysql
#import datetime
import socket
## python3 -m pip install PyMySQL


ip = list(range(1, 9)) # Printer IP-List 41 to 49
name = ["xx", "UMA", "UMB", "UMC", "UMD", "UME", "UMF", "UMG", "UMH"] 
maschinenzahl = len(ip) 

for x in ip:
    #print ("XXXX=",x)
    response = os.system("ping -c 1 192.168.42.4"+str(x))
    if response == 0:
        pingstatus = "Network Active"
        
        # Create a client socket
        clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
        clientSocket.connect(("192.168.42.4"+str(x),34568));
        # Send data to server
        data = '{"read":"global_counter"}';
        clientSocket.send(data.encode());
        # Receive data from server
        dataFromServer = clientSocket.recv(140);
        clientSocket.close()

        #Counter des ersten Druckkopfes auslesen.
        zaehler=int(dataFromServer.decode().split(",")[1])
        print ("z1:",zaehler," an Maschine",x,"mit Name:",name[x])

        time.sleep(2) # Sleep for 2 seconds
        
        # Connect to the database 
        connection = pymysql.connect(host="192.22.76.25",user="uni-xxxx",password="xxxxxxx",database="unimaschinendrucker")


        # https://www.tutorialspoint.com/python/python_database_access.htm
        try:
            with connection.cursor() as cursor:
                # Create a new record
                sql = "INSERT INTO `statistik` (`Maschine`, `Menge`) VALUES (%s, %s)"
                cursor.execute(sql, (name[x],zaehler))

            # connection is not autocommit by default. So you must commit to save
            # your changes.
            connection.commit()

        except:
        # Rollback in case there is any error
            connection.rollback()

        finally:
            connection.close()
    else:
        pingstatus = "Network Error"
        print ("Maschine ",x,name[x]," nicht erreichbar !\n\n\n")
        #print ("------------------------------------------------------------------")

Hallo juergen852,

vielen lieben Dank das du dein Code teilst. Ich werde morgen schauen ob ich dein Code in SCL programmieren kann. Die Verbindung im TIA und das lesen der Daten hatte ich aktuell mit dem Baustein TRCV_C gemacht und hätte über Daten jetzt irgendwas lesen wollen. Scheint wohl komplizierter als gedacht zu sein.

Bist Du weiter gekommen?
Ich habe damals mehrfach mit deren Support telefoniert und je nach dem wen man da dran bekommt, können die auch etwas helfen.

Hallo juergen852,

ja dank des wahnsinnig guten Supports wurde mein Anliegen wunschlos gelöst. Nochmals vielen lieben dank auch hier für die Unterstützung.

LG
Torsten