Serielle Schnittstelle (RS232) über Modul zur Verfügung stellen

Hallo Leute,

manchmal Dingen fehlen einem so die richtigen Ideen…

Ich möchte über ein Modul eine serielle Schnittstelle zur Verfügung stellen. Diese sollten - wenn sie dann eingebunden ist - vom IPS her möglichst so bedient und abgefragt werden wie eine „normale“ serielle Schnittstelle.
Ich grübele schon die ganze Zeit, wie man das wohl am Besten anstellt…

  • Wäre da die RegisterVariable da der richtige Ansatz?
  • Wenn ist so ist, wie binde ich diese überhaupt in mein Modul ein?

Bin für Denkanstösse und Tipps dankbar…

Joachim

Schau dir mein WebSocket Modul, den ClientSplitter an.
Der stellt die übliche IPS interne IO zur Verfügung.
Oder meinst du, du möchtest eine serielle in deinem Modul ansprechen? Also andere Richtung?!
Michael

Hallo Michael,

ich möchte die serielle Schnittstelle eines entfernten Raspberry Pi zur Nutzung durch ein Modul einbinden.
Durch eine einfache public function kann ich es relativ leicht realisieren, dass dort Daten hingesendet werden, nur was mache ich am Besten - um dieses Funktion auch möglichst universel nutzbar zu machen - mit den Daten die zurückkommen? Das könnte ja ziemlich „wilde“ Zeichenfolgen sein und der Nutzer muss diese in fast allen Fällen ja irgendwie weiterverarbeiten.
Wenn der Nutzer einen „echten“ SerialPort" im IPS installiert, wird er doch die ankommenden Daten in der Regel auf eine Registervariable schicken, die dann ein Skript zur Verarbeitung antriggert. In der Dokumentation steht, man soll die ankommenden Daten nicht auf eine „normale“ Stringvariable schreiben…

Joachim

Verwendest Du auf dem Remote PI ser2net zur Umleitung serielle Schnittstelle IP-Socket und auf dem lokalen Pi einen normalen Clientsocket. Fertig. So mache ich es bei meinem Busware COC.

Tommi

So auf keinen Fall umsetzen.

Bitte dieses Thema durcharbeiten:
Datenfluss — IP-Symcon :: Automatisierungssoftware

Du musst dann in deinem Modul den Virtual I/O als Interface für die Childs implementieren.
Außerdem musst du ja irgendwie die Daten vom RPi bekommen, auch dafür brauchst du ja bestimmt einen IO. Sprich ClientSocket o.ä.
Auch dafür musst du ein Interface in deinem Modul implementieren.

Hier gibt es ein Beispiel von Paresy:
SymconTest/module.php at master · paresy/SymconTest · GitHub

Daten Buffern musst du selbst ja gar nicht und kannst dich ‚transparent‘ verhalten.
Das ist dann die Aufgabe des Users mit Hilfe einer RegVar, welcher er hinter dein Modul hängt.

Michael

PS: ClientSocket und Serielle Schnittstelle bilden das gleiche Interface ab und sind in IPS untereinander austauschbar. Dafür braucht es kein Modul.

Hallo Tommi und Michael,

ofensichtlich muss ich jetzt doch noch mal etwas ausholen:
Selbstverständlich benutzt mein Modul eine ClientSocket und dabei auch die Wege die im Datenfluss beschrieben sind. Wenn man es genau nimmt, sind es sogar zwei: Eines für die Kommandos und eines für den Empfang „unangefragter Daten“. Die Kommunikation besteht darin, auf dem entfernten Pi GPIO, I²C, die serielle Schnittstelle und 1-Wire zu steuern und die Ergebnisse im IPS darzustellen. Alles so weit so gut - bis auf ein paar Details wie im anderen Thread beschrieben.

Auch die Kommunikation aus dem Splitter-Modul hin zum Pi wird über diese beiden ClientSockets laufen - intern. Wenn jemand etwas zur seriellen Schnittstelle senden möchte, macht er einen Funktionaufruf der dann aufbereitet und wie im Datenfluss beschrieben über den ClientSocket zum entfernten Pi gesendet wird. Neben vielen anderen Daten aus 1-Wire, I²C usw. kommen die Daten über den ClientSocket und über die im Datenfluss beschrieben Wege wieder zum Splitter und werden an die Instanzen verteilt.

Bei der seriellen Schnittstelle gibt es aber keine konkrete Funktion - anderes als bei I²C z.B. wo nur definierte Bausteine zugelassen sind. Die aus dem Pi kommenden Daten der seriellen Schnittstelle sollen nun aus dem Splitter an eine „universelle“ Schnittstelle gesendet werden, damit der Nutzer selbst diese Daten weiterverarbeiten kann - und da dachte ich eben daran, diese an einen RegisterVariable zu senden, wo der Nutzer eben das Skript definieren kann, was ihm die ankommenden Daten weiterverarbeitet…

Ist das so nachvollziehbar?

Im Moment habe ich das versuchsweise mal so realisiert:

  • Funktionsaufruf im Splitter mit dem zu sendenen Text „Test“
  • Die Daten werden aufbereitet und in diesem Fall über meinen „CommandClientSocket“ an den entfernten Pi gesendet
  • da ich RX und TX dort verbunden habe bekomme ich die Daten zurück
  • ich visualisiere sie und der Text ist „Test“

Ich könnte jetzt ja auch folgendes machen:
Ich gönne meinem Modul eine weitere Stringvariable und schreibe den empfangenen Text dort herein, der Nutzer überwacht diese Stringvariable auf Änderungen und verarbeitet diese dann - das sollte doch aber wohl so nicht sein, oder…:smiley:

Es geht also lediglich um die regelkonforme Visualisierung bzw. die zur Verfügungstellung der ankommenden Daten…:wink:

Joachim

Auch nicht machen.
Rohdaten haben in IPS-Variablen nichts zu suchen.

Du musst die Daten schon per SendDataToChildren weitersenden an einen Child (welche das ist, ist ja egal).
So dass der User dann dort eine RegVar hinter hängt und dann kann er im Script mit den Daten machen was er will.
Oder es schreibt jemand ein Modul und hängt es dort hinter, auch egal.

Zum senden von diesem Child über deinen Splitter musst du aber auf jeden Fall auch das ForwardData umsetzen, sonst kann weder die RegVar noch eine andere Instanz hinter deinem Splitter die Daten versenden.
Deine Public-Funktion ist ein Addon, was auch jede IPS-IO-Instanz hat; braucht man aber nicht wirklich.

Beispiel: (Ersetze serielle Schnittstelle + ZigBee-Module durch deine Splitter und IOs)

Michael

Hallo Michael,

gefühlt bin ich jetzt wieder bei meiner Eingangsfrage.:frowning:

Bei einem „echten“ IPS-SerialPort wäre der Syntax um etwas zu senden

SPRT_SendText(12345, "Beliebiger Datensatz");

bei mir wäre es so etwas wie

MeinModul_SendText(12345, "Beliebiger Datensatz");

sieht nach außen damit nahzu identisch aus…(und klingt in beiden Fällen nach einer PublicFunction)
Ob diese dann im Splitter direkt hängt oder darunter noch ein Child ist dabei vielleicht erst einmal zweitrangig und im Zweifel schnell gemacht…

Aber wie realisiere ich den auch von Dir gezeigten Weg „So dass der User dann dort eine RegVar hinter hängt…“, also die Datenausgabe?

Joachim

Nachtrag: Die IPS-RegisterVariable kann ich meinen Splitter nicht als übergeordnete Instanz zuweisen. Mein (neu zu schaffendes) Child könnte also die Funktion der RegisterVariablen abbilden. Wie würde ich dem „Ziel-Skript“ die ankommenden Daten als $_IPS[‚VALUE‘] übergeben?

SPRT_SendText ist aber nur ein Addon.
Du musst zusätzlich auch ForwardData umsetzen!
Eigentlich sendet man über die RegVar mit RegVar_SendText.

Und die andere Richtung habe ich dir schon aufgezeigt.
Du musst die Daten per SendDataToChildren weitersenden.
Michael

Okay, super, dann habe ich erst einmal ein Plan!:slight_smile: Danke!

Eine Frage noch: Wie gebe ich dem Zielskript des Nutzers die ankommenden Daten im $_IPS[‚VALUE‘] „mit“?

Joachim

Gar nicht, du startest kein Script!
Das macht die RegVar.
Michael

…das wird so nicht funktionieren befürchte ich…
Die IPS-RegVar akzeptiert meinen Splitter nicht als übergeordnete Instanz, müsste aber so sein, da die Daten noch vor dem Senden aufbereitet werden müssen, umgekehrt müssen die ankommendenDaten erst herausgefiltert werden und dann an „mein“ RegVar-Child übergeben werden.
Das heißt, ich erstelle etwas was aussieht wie ein IPS-RegVar und der User kann ein Zielskript wählen, dazu muss ich dem gestarteten Skript aber die Daten „mitgeben“…

Joachim

Dann musst Du Deinem Splitter die entsprechenden Interfaces (Implements) mitgeben

Auch nicht machen.
Warum etwas neues erfinden, wenn IPS funktionierende Mittel hat.
Dann kann keine andere Instanz sich an deine Instanz als Child anhängen und alle Skripte welche für eine RegVar ausgelegt sind, funktionieren auch nicht.
Zusätzlich müsstest du dem User einen Buffer zur Verfügung stellen.

Alles Aufwand und Umwege welche du in Kauf nimmst.

Mach es so wie Tommi es schreib; vermutlich hast du in der Modul.json irgendeine falsche / fehlende GUID.
Michael

…wenn das so klappen würde, wäre das mit Sicherheit die beste Variante!

Bin jetzt aber (wieder) etwas am Schwimmen:
Wie sind denn die GUID für RX und TX?
Die RegVar wäre ja in diesem Fall das Device?
Und weiß die RegVar dass sie jetzt nicht I/O sondern Device ist? Ich kann dort doch nichts eintragen?

Joachim

Du trägst bei der RegVar gar nix ein.
Die GUIDs stehen in der Doku und die hatte ich Verlinkt:
https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/datenfluss/

Du musst dann in deinem Modul den Virtual I/O als Interface für die Childs implementieren.
Michael

Hallo Michael und Tommi,

auch auf die Gefahr hin, dass ich hier gleich geschlagen werde - ich habe es noch nicht verstanden…:mad:

Derzeit ist die Struktur so:

  • Client Socket
  • Splitter
  • 1 - n-Devices

Nun habe ich im Splitter die Code-Bestandteile, die für alle Devices die Kommunikation

  • von den Devices über den Splitter zum Client Socket und
  • vom Client Socket über den Splitter zu den Devices
    abarbeiten

Jetzt zu dem was ich meine verstanden zu haben:

  • es soll eine virtuelle I/O hinzugefügt werden
  • an diese virtuelle I/O kann der Nutzer eine IPS-RegVar hängen
  • der Nutzer kann dann über REGVar_SendText Daten senden
  • und über das anzugebene Zielskript ankommenden Daten auswerten

Nur wo soll ich jetzt den Virtuellen I/O ranhängen? Kann ein Device oder ein Splitter denn zwei Parents haben?:confused:
DIE RX/TX GUID sind ja gleich den der schon verwendeten Client Socket. Muss dann beim Start zwei RequireParent in den Code?

Sorry, wenn ich (noch mal) so blöd nachfrage…

Joachim

Also wenn du einen zweiten IO zur Hardware brauchst, dann kommt das natürlich nicht in deinen Splitter sondern wird eine ganz neues eigenes Modul.

Wenn du jedoch einen I/O hast und dann dein Splitter… was hindert dich daran, außer die Verbindung zu deinen Devices, eine Verbindung zu anderen Devices (Virtual-IO Interface) umzusetzen.

Beispiel:

Mein WebSocketClient ist ein Splitter und hat einen Clientsocket als übergeordneten IO.

Ich sende dann die Daten einfach an mehrere Interfaces :slight_smile:


        $JSON['DataID'] = '{018EF6B5-AB94-40C6-AA53-46943E824ACF}'; // Virtual IO RX (Virtual IO TX = {79827379-F36E-4ADA-8A95-5F8D1DC92FA9})
        $JSON['Buffer'] = utf8_encode($RawData);
        $Data = json_encode($JSON);
        $this->SendDataToChildren($Data);


        $JSON['DataID'] = '{C51A4B94-8195-4673-B78D-04D91D52D2DD}'; // WSC Receive ; (WSC Send ist {BC49DE11-24CA-484D-85AE-9B6F24D89321})
        $JSON['FrameTyp'] = $this->PayloadTyp;
        $Data = json_encode($JSON);
        $this->SendDataToChildren($Data);

Entsprechend viele GUIDs sind in der implemented

    "parentRequirements": ["{79827379-F36E-4ADA-8A95-5F8D1DC92FA9}"],
    "childRequirements": ["{018EF6B5-AB94-40C6-AA53-46943E824ACF}","{C51A4B94-8195-4673-B78D-04D91D52D2DD}"],
    "implemented": ["{018EF6B5-AB94-40C6-AA53-46943E824ACF}", "{79827379-F36E-4ADA-8A95-5F8D1DC92FA9}","{BC49DE11-24CA-484D-85AE-9B6F24D89321}"],

Hier ist das sehr einfach da die Daten ja den gleichen Nutzen haben.

Bei den XBees ist es z.B. ganz anders.
Da wird mal ein serielles Datenpaket empfangen und muss an den Virtual-IO zum nächsten Splitter/RegVar.
Und mal eine Veränderung der A/D Pins übertragen welches ich dann an eine Geräte-Instanz senden muss.
Also ein Datenstrom rein… auseinanderdrösseln und weiter senden an verschieden Interfaces.
Funktioniert super (darum heißt das Ding ja auch Splitter :wink: )

Michael