Frage an die Modulentwickler (bzw. wo finde ich die geheime Doku)

Hallo Uwe,

um zu sehen wie die Kommunikation funktioniert, habe ich mir bei einem meiner ModBus-Projekte einen „Fake-Splitter“ erstellt. Dann siehst Du was da von den „echten“ Instanzen ankommt:
GitHub - Joey-1970/IPS2Broetje: Anbindung einer Brötje-Heizung über ModBus an IPS

Joachim

Erstmal ein frohes neues Jahr,

@paresy Ich glaube Du hast mein Anliegen nicht verstanden. :confused:

Modbus ist ja jetzt keine Raketenwissenschaft wofür es ein NDA geben könnte? :smiley:

Ich habe in der offiziellen Dokumentation keinen Hinweis gefunden, wie bei den Modulen die Anbindung an das ModBus Gateway funktioniert.
Ein paar Hinweise in der offiziellen Doku über den Datenfluss des ModBus Gateway analog wie für (Client Socket, HID, HTTP Client, …) ist ja jetzt keine große Sache.
Eine Referenz auf einen Beispielcode mit ein paar zusätzlichen Hinweisen im Code hätten mir auch gereicht.

Mein Ergebnis aus „Jugend forscht“ sieht wie folgt aus. Vielleicht kann das jemand anderes gebrauchen.
Falls ich falsche Rückschlüsse gezogen habe bitte berichtigen.


	class MODBUS extends IPSModule {

		public function Create()
		{
			//Never delete this line!
			parent::Create();

			// verbinde ein ModBus Gateway 
			$this->ConnectParent("{A5F663AB-C400-4FE5-B207-4D67CC030564}");

		}

		public function Destroy()
		{
			//Never delete this line!
			parent::Destroy();
		}

		public function ApplyChanges()
		{
			//Never delete this line!
			parent::ApplyChanges();
		}

		public function ModBusRequest()
		{
			// $DataID ist die [Implemented] GUID des ModBus Gateway. 
			// Lässt sich mit folgendem Befehl ermitteln:  IPS_GetModule("{A5F663AB-C400-4FE5-B207-4D67CC030564}")
			$DataID = "{E310B701-4AE7-458E-B618-EC13A1A6F6A8}"; 
			
			// ModBus Adresse des Gerätes. Die ModBus Geräte ID wird direkt im Modbus Gateway konfiguriert. 
			$Address = 0x0000;

			// ModBus FunctionCode zur Abfrage bzw. Senden von Parameter. (Siehe https://de.wikipedia.org/wiki/Modbus)
			$Function = 4;

			// Anzahl der Datenregister
			$Quantity = 2;

			// Datenbyte String, zum Schreiben an ModBus (Bei FunctionCodes 5,15,6,16) 
			$Data = "";

						
			$response = $this->SendDataToParent(json_encode(Array("DataID" => $DataID, "Function" => $Function, "Address" => $Address , "Quantity" => $Quantity, "Data" => $Data)));
			// $response[0] => gesendeter Function Code
			// $response[1] => Anzahl der folgenden Werte Bytes (angefordert mit $Quantity)
			// $response[2] bis  
			// $response[x] => Werte Bytes. Die Reihenfolge ist unabhängig von der Einstellung von "Swap LSW/MSW" im Modbus Gateway !! 

			$this->SendDebug("ModBus Response", $response, 1);
			
		
		}


	}

Ich klinke mich hier mal ein. Ich bin auch grade dabei ein Modul zu schreiben für eine EOS Saunasteuerung die über ModBus angebunden ist.
Leider bekomme ich es nicht hin, die Parent Instanz in der Create Funktion einzubinden. Wenn ich den Code wie ich hier erfahren habe verwende:

class EOSModBus extends IPSModule
		public function Create()
		{
			//Never delete this line!
			parent::Create();
			$this->ConnectParent('{A5F663AB-C400-4FE5-B207-4D67CC030564}');			
			
			$this->CreateVariableProfiles();

			$this->RegisterPropertyInteger("Vaporizer", 1);
			$this->RegisterPropertyInteger('Interval', 0);
			$this->RegisterTimer('UpdateTimer', 0, 'EOS_RequestRead($_IPS["TARGET"]);');
		}

bekomme ich die Meldung:

Warning:  Datenfluss ist inkompatibel in C:\ProgramData\Symcon\modules\EOSModBus\EOSModBus\module.php</b> on line 34
 (Code: -32603)
Edit:

Ich hab es grade selbst gefunden, man muss die Datei modul.json entsprechend anpassen, dann läuft es zumindest schon mal durch.

1 „Gefällt mir“

So ich bekomme meine Steuerung schon mal ausgelesen. Das geht mal super fix und mal dauert es ewig kein Ahnung warum. Ich bekomme aber fast immer am Ende der Schleife in der ich alle Daten hole einen Fehler „Zeitüberschreitung beim Warten auf Antwort“ aber die Daten werden meistens trotzdem gelesen und angezeigt. Und ab und zu auch die Meldung „ILLEGAL_DATA_ADDRESS“ was aber scheinbar nur passiert wenn ich versuche ein Register auszulesen, dass in meinem Fall zwar vorhanden ist, das aber keine Daten enthält. Dann hab ich noch den Fall, dass teilweise bei einem Lauf keine Daten geliefert werden.
Und dann kommt auch ab und an nur „UNKNOWN_ERROR“.

Das Verhalten ist irgendwie nicht vorher zu sehen.

Fragen:
Kann ich das Verhalten irgendwie analysieren?
Und wie kann ich die Meldung unterdrücken? Mit try / catch scheint es nicht zu gehen.

Am besten wäre es, wenn du mal im Debug (Der I/O Instanz oder im Splitter) schaust was für Daten gesendet werden.

Übrigens gibt es hier ein Modul, welches die ModBus Abfragen macht: SymconBC/module.php at master · symcon/SymconBC · GitHub

paresy

Das ist ein sehr schönes und anschauliches Beispiel vielen Dank dafür.

Ich hab das jetzt mal auf eine eigene Entwicklungsmaschine geschoben und auch nur noch die Steuerung am Modbus hängen und jetzt sieht es ganz gut aus. Allerdings bekomme ich immer bei der letzten Adresse die ich lese zwar den Wert aber danach den Fehler „ILLEGAL_DATA_ADDRESS“.

Jetzt befasse ich mich grade mit dem Schreiben von Werten. Das scheint auch noch nicht so einfach zu sein. Ich würde das gerne so machen, dass durch die Änderung der Variablen das Schreiben ausgelöst wird. Das passiert in RequestAction richtig? Aber wie müssen die Daten aussehen die gesendet werden? Ein einfacher String scheint es nicht zu sein wenn ich da z.B. 80 Als Wert übergebe zeigt mir das System später 48 an. Ich gehe mal davon aus, dass da was umgewandelt werden muss da das wohl Hex Werte sein müssen?.

Das funktioniert nicht. Zumindest nie über die Änderung des Wertes der Variable.
Es gibt aber die Anforderung einen Wert zu setzen, welches durch die Visualisierungen bzw. im Script durch RequestAction ausgelöst wird.
Diese Anforderungen landet dann, wie schon korrekt erkannt, im Modul in der Methode RequestAction.
Das ist die sogenannte Standardaktion einer Variable, welche du aber erst mit EnableAction auf deine Variable aktivieren musst.
Wie die Werte beim Schreiben genau sind, kann ich dir nicht sagen. Auf jeden Fall ist String (Datentyp) der Inhalt dürfte aber binary sein.
Michael

Zum Thema schreiben: Ich wandle einen Integer Wert in einen String und den übergebe ich. Kann es sein, dass da ein anderes Datenformat benötigt wird? Ich bekomme dabei keinen Fehler aber schalten tut das Gerät auch nicht.

Kann ich irgendwo den Code für das ModBus Devide finden? Da wird das doch auch gemacht und funktioniert.

Was heißt wandeln?
Nur die Zahl als Datentyp String versenden oder die Zahl in ihre binären Entsprechung?
Zeig doch einmal dein Code.
Irgendwo hatten wir das Thema im Forum schon einmal. Bin aber gerade auf den Sprung und kann somit nicht suchen.
Michael

Ich glaube es hat sich erledigt. Natürlich muss ich pack verwenden um aus dem Int den richtigen String zu bauen. Sorry für die Verwirrung!

Was ich jetzt noch brauche ist die Info, wie ich diese Action aufrufe wenn ich den Wert im Webfront ändere. Sprich wie kann ich die Standardaktion setzen wie z.B. das eigene Profil?

Ach ja und drei Fragen hab ich noch,

  • wie kann ich mein Modul aus einem Skript heraus aufrufen?
  • wie macht man es am geschicktesten diese Funktion „Status emulieren“ mit einzubauen (auch im Form) und zu verwenden?
  • wie kann ich meine Switches anwenden? Genau wie alle anderen auch?

Der neue Wert landet mit dem Ident der Variable in der Methode RequestAction von deinem Modul.
Kennst du die Test/Demo Module?

Michael

Ja genau so mache ich das auch und über den Punkt „Befehl testen“ funktioniert das Schalten auch.

Public Methoden werde als Instanz-Funktionen von Symcon verstanden. Dazu kommt davor das Präfix aus der module.json. Das steht auch in der Doku :wink:
Beispiel:

Zuerst im Abschnitt Konfigurationsformular der SDK Doku einmal die benötigten Elemente (CheckBox) raussuchen. Und wie man Eigenschaft einer Instanz registriert und liest: RegisterPropertyBoolean — IP-Symcon :: Automatisierungssoftware
Dann kannst du vor dem Senden prüfen ob die Eigenschaften aktiv ist oder nicht.

Sorry, verstehe die Frage nicht :sweat_smile:
Michael

OK die letzte Frage war vielleicht etwas aus der Hüfte geschossen :joy:

Bleibt nur noch die Frage nach der Standardaktion.

Die wurden doch beantwortet :confused:
Aktion aktivieren mit EnableAction (SDK Doku)
Und dann in RequestAction den ident und wert verarbeiten.
Michael

OK hab ich gemacht aber das läuft noch nicht, werde ich mir aber noch mal näher ansehen.

Auf jeden Fall hab ich mir das Ganze jetzt im Webfront angeschaut und wenn ich da irgendetwas einstelle kommt es sauber an der Steuerung an. Ich bin sehr begeistert.

Wenn ich jetzt noch raus bekomme wie ich die ab und an kommenden Meldungen über Zeitüberschreitung raus bekomme ist das Teil für mich perfekt nutzbar. :ok_hand:

Der Beitrag hier oben, genauer das verlinkte TestModule ist genau das.
Eine Variable ‚TestVariable‘ mit Standardaktion und dann in RequestAction die Verarbeitung der Aktion. In diesem TestModule wird einfach nur die Variable gesetzt. Du müsstest dann deine Schreibfunktion ausführen.

Michael

Ja genau das mache ich. Beim Schalten über das Webfront funktioniert es auch. Beim Ändern des Wertes über den Objektbaum nicht. Ist aber egal, da es mir darauf ankommt das Element sauber über die Oberfläche bzw. ein Skript setzen zu können.

		public function RequestAction($Ident, $Value) 
        { 
            switch ($Ident) 
            { 
                case 'eosSetTempValue':
                    $this->SetTempValue($Value);
                    break;
                default:
                    break; 
            }
        }

		public function SetTempValue(int $Value)
        {
            if($Value < 30) {$Value = 30;}
            if($Value > 115) {$Value = 115;}
            if ($this->ReadPropertyBoolean('StatusEmulieren') == true)
            {
                $this->SetValue('eosSetTempValue', $Value);
            }
            $this->WriteData(151, $Value);
        }

		private function WriteData($Address, $Value)
		{
			$DataID = "{E310B701-4AE7-458E-B618-EC13A1A6F6A8}"; 
			$Function = 6;
			$Quantity = 2;
			$Data = pack('n', $Value );

			set_error_handler([$this, 'ModulErrorHandler']);
			$response = $this->SendDataToParent(json_encode(Array("DataID" => $DataID, "Function" => $Function, "Address" => $Address , "Quantity" => $Quantity, "Data" => $Data)));
			restore_error_handler();
			
			return true;
		}

Richtig!
Das ging noch nie, auch nicht bei Symcon internen Modulen.
Michael

Ahhhh dann kann ich ja lange suchen. Dann bin ich also mit dem Teil fertig.
Vielen Dank für de geduldige Antworten! Ist auch nicht überall selbstverständlich.
Schönes Wochenende!