Modulerstellung: Frage zum erstellen eines Objektlink im Modul

Aktuell arbeite ich an einem Modul, hierbei möchte ich einen ObjectLink verwenden.

Im Konfigurationsformular wird ein Sensor ausgewählt:
instanzkonfiguration

Die ID des ausgewählten Sensorwerts, soll anschließend im Objectlink hinterlegt werden.

Hierzu habe ich ein paar Fragen:
In der public function Create, habe ich den Link wie folgt angelegt:

		$ist_luftfeuchtigkeit	= IPS_CreateLink();					//Create link
		IPS_SetName($ist_luftfeuchtigkeit, "Luftfeuchtigkeit");   	//Name the link
		IPS_SetParent($ist_luftfeuchtigkeit, $this->InstanceID);    //Set a parent

Nach Erstellung sieht das ganze aktuell so aus:

Den Befehl „IPS_SetLinkTargetID“ kann ich bei der Erstellung der Instanz noch nicht verwenden, da erst nach Erstellung der Instanz im Instanzkonfigurator ausgewählt wird auf welche Variable der Link verweisen soll, da diese Info vorher noch nicht vorhanden ist.

Meine Frage:
An welcher Stelle bw. wie weiße ich dem Link jetzt noch die TargetID zu auf die er verweisen soll?

Ich dachte das ganze mache ich dann unter „public function ApplyChanges“ das funktioniert aber nicht.

Das ganze könnte wie folgt auch direkt im „ApplyChanges“ bereich untergebracht werden:

$ist_luftfeuchtigkeit	= IPS_CreateLink();					//Create link
IPS_SetName($ist_luftfeuchtigkeit, "Luftfeuchtigkeit");   	//Name the link
IPS_SetParent($ist_luftfeuchtigkeit, $this->InstanceID);    //Set a parent
 IPS_SetLinkTargetID($ist_luftfeuchtigkeit, TARGETID);

Diese Lösung finde ich aber nicht so schön, da die Instanz erst erstellt wird ohne den Objectlink.
Diese wird dann erst angelegt, sobald man eine ID im Instanzkonfigurator ausgewählt hat und einmal auf „Änderungen Übernehmen“ geglickt hat.

Habt ihr einen Tipp für mich? Wie handhabt ihr das wenn ihr in Modulen arbeite in Bezug auf Objectlinks.

Zusammengefasst:
In der „Create“ Funktion soll ein Objektlink angelegt werden.’
Anschließend soll, sobald eine Variable im „Instanzkonfigurator“ ausgewählt wurde die ID im erzeugten Objektlink hinterlegt werden, nachdem das ganze mit „Änderungen übernehmen“ bestätigt wurde.

Ich Handhabe das ganz einfach.
Ich nutze einfach keine Links. Wozu auch…
Edit: naja stimmt nicht ganz. Mein DynamicVisuControl nutzt Links.
Die werden aber nur bei Bedarf angelegt.
Dafür gibt es dann da keine Variablen, weil es ja eine Instanz rein für die Visualisierung ist.
Also nix gemischtes mit Variablen & Links, wo der User nachher nicht weiß was er selber angelegt hat oder was zur Instanz gehört.
Michael

Guten Abend Nall-chan,
darüber habe ich auch schon nachgedacht, ob ich Links oder „neue Variablen“ verwende.

Der Hintergrund war hier, das wenn ich mir z.B. KNX-Gruppenadressen / Sensoren erstellen lasse,
dort immer schon eine Variable habe in dem z.B. der Ist-Temperaturwert steht.

Mit einem Link spare ich mir eine Variable in Hinsicht auf die Lizenz.
Übertriebenes Beispiel zur Verdeutlichung: Ich binde 100 Temperatursensoren ein, wenn ich ohne Links arbeite benötigte ich 200 Variablen anstatt 100 Variablen.

Grundsätzliches würde es mich aber trotzdem interessieren ob man mit den Links so lösen kann wie ich es mir vorgestellt habe.

Deinen Hintergrund mit der nach Vollziehbarkeit kann ich aber auch sehr gut verstehen.

Hier einmal ein Script, vielleicht sieht jemand was:

<?php

// Klassendefinition
class raumklima extends IPSModule {
    // Überschreibt die interne IPS_Create($id) Funktion
    public function Create() {
        // Diese Zeile nicht löschen.
        parent::Create();

		// Erstellen der Variablen im Objektbaum mit Positionswert am Ende	
		// Erstellung eines Links
		

		$ist_luftfeuchtigkeit	= IPS_CreateLink();					//Create link
		IPS_SetName($ist_luftfeuchtigkeit, "Luftfeuchtigkeit");   	//Name the link
		IPS_SetParent($ist_luftfeuchtigkeit, $this->InstanceID);    //Set a parent
		#IPS_SetLinkTargetID($ist_luftfeuchtigkeit, 0);    			//Attach the link
		
		// Erstellung neuer Variablen im Objektbaum
		$status_lueften     	= $this->RegisterVariableFloat("status_lueften", "Status","",1);
		$grenzwert      		= $this->RegisterVariableFloat("grenzwert", "Grenzwert","",2);
		$meldeverzoegerung    	= $this->RegisterVariableFloat("meldeverzoegerung", "Meldeverzögerung","",3);


		// Variablen (im Hintergrund) für den Inhalt aus dem Konfigurationsformular (form.json)
		$this->RegisterPropertyInteger("ID-Luftfeuchtigkeit", 0);
		#$this->RegisterPropertyInteger("ID-Link", $ist_luftfeuchtigkeit);



		// Create variable profile


        // Assign icon to variable profile


        // Assign variable profile


    }
    // Überschreibt die intere IPS_ApplyChanges($id) Funktion
    public function ApplyChanges() {
        // Diese Zeile nicht löschen
        parent::ApplyChanges();





		// Hier werden Änderungen auf die erstellte Formular-Variable mithilfe "RegisterMessage" registriert
		if($this->ReadPropertyInteger("ID-Luftfeuchtigkeit") > 0) {
        	$this->RegisterMessage($this->ReadPropertyInteger("ID-Luftfeuchtigkeit"), VM_UPDATE);
			// ReadPropertyInteger: Die Funktion gibt den Wert der Eigenschaft mit dem Namen Name zurück.
        }

    }



    public function MessageSink($TimeStamp, $SenderID, $Message, $Data)
    {
	   $value = $this->ReadPropertyInteger("ID-Luftfeuchtigkeit");
	   IPS_SetLinkTargetID($ist_luftfeuchtigkeit, $value);
	   IPS_LogMessage("MessageSink", "New message!!!");
    }

Ja, klar kann man das.
Dein Beispiel wird so natürlich nicht funktionieren, weil du dem Link-Objekt keinen Ident gegeben hast, um anschließend das Objekt wieder zu ermitteln.

Michael

Guten Morgen Nall-chan,
okay, das mit „GetIDForIdent (string $Ident)“ ist verstanden, warum der Befehl nötigt ist.

Die Nächste Frage: Was ist der Ident des Links?
Der Name des Links ist „Luftfeuchtigkeit“ was aber nicht gleichzeitig der Ident ist.
Und beim erstellen des Links lege ich keinen Ident fest.
Kannst du mir noch einen Tipp geben?

Ich könnte auch „IPS_GetObjectIDByName“ verwenden, das möchte ich aber vermeiden da sich der Name des erstellen Links ändern kann (z.B. nach einer manuellen Umbenennung) und das ganze dann nicht mehr funktionieren würde.

Die Frage ist schon falsch :wink:
Korrekt wäre:

Was ist der Ident vom Objekt.

Das ist der, welchen du vergibst. Hast du keinen Vergeben, geht es natürlich nicht.

Nein, kannst du nicht, wie du schon richtig erkannt hast. Namen liegen in der Hoheit der User.

Bitte schau dir andere Module an, die Best Practice zur PHP-Modul Erstellung und eventuell noch das erste Entwickler Video Kapitel Ident.

Michael

Warum ich mir grad so schwer tue ist das es keine „normale Variable“ ist sondern ein Link und ich da einfach nicht weiß, wie ich diesem einen Ident zuweise, aber wie es scheint, geht genauso wie bei einer Variablen.

Das Entwicklervideo habe ich mir schon mehrfach angeschaut, das hat mir auch schon sehr weitergeholfen. Den anderen Link schaue ich mir noch an. :slight_smile:

Ich melde mich nochmal, wenn ich das ganze erneut ausprobiert habe.

EDIT:
Zuweisung des Ident scheint mit „IPS_SETIDENT“ zu funktionieren.

Genau, darum auch ruhig bei anderen Modulen spicken und die Suche auf der Symcon Website funktioniert auch für die Dokumentation, falls man zwar den Begriff kennt, aber die Funktion halt nicht.
Alles was deine Instanz erstellt immer mit einem Ident versehen, egal ob Link, Media o.a. Objekte.
Dann funktioniert das Modul unabhängig von ObjektIDs und Namen.
Michael

1 „Gefällt mir“

Ja, für Links gibt es bisher keine Register-Funktion, daher müsste man das genau so machen, wie ihr das erarbeitet habt. Es ist sicherlich eine Geschmacksfrage, aber ich würde es tatsächlich schöner finden, den Link in ApplyChanges zu erstellen. Dann gibt es nämlich einfach keinen Link, falls kein Ziel gewählt ist und keinen der ins Leere zeigt. Das wäre tatsächlich auch relevant für die Sicherheit. Standardmäßig zeigt ein Link ja auf die Hauptkategorie, was der entsprechenden Visualisierung möglicherweise ungewollt Zugriff auf das gesamte System gibt.

Oh, das ist ein sehr guter Hinweis. Vielleicht könnte man Links ja auch die Möglichkeit von ‚kein Ziel gewählt‘ hinzufügen.
Michael

Man kann halt ein ungültiges Ziel, z.B. 1, wählen. Aber ein Link hat halt initial als Ziel eine 0 stehen, sprich die Hauptkategorie

Das sind ein Interessanter Aspekte, so habe ich das noch gar nicht gesehen bzw. betrachtet.
Vielen Dank für die Hinweise.

Beide Varianten 50 / 50 haben ihren Vorteil / Nachteil.

Wenn der Link nicht gleich bei der Erstellung der Instanz erstellt wird, dann kann es für den User verwirrend sein weil er einen Wert bzw. in diesem Fall den Link vermisst.

Vom Sinn her das ganze in Apply Changes auszuführen, wenn man die ID, die dem Link zugewiesen werden soll, ausgewählt hat, wäre vom Sicherheitsaspekt besser.

Der Vorschlag von Nall-chan kein Ziel automatisch auszuwählen (auch nicht 0) würde beides vereinbaren. Aber es scheint das, das nicht möglich ist sowie ich Dr. Niels verstehe.

Doch, kannst doch im create einfach auf 1 setzen. Ist dann halt ungültig (im Frontend).
Michael

Musst du ja gar nicht im Create machen, ApplyChanges reicht ja aus. Immer wenn Create ausgeführt wird, wird ja auch ApplyChanges ausgeführt. Ist ja auch einfach, dann gibst du einfach den Wert der Eigenschaft weiter, egal ob die jetzt noch bei 1 oder bei einem korrekten Wert steht.

Hallo Leute,
vielen Dank noch einmal für eure Hilfe, ich habe es geschaft.
Auch mit einer Überprüfung ob der Link bereits vorhanden ist, um nur dann einen Link zu erstellen, wenn noch keiner vorhanden ist.

        $linkID = @IPS_GetObjectIDByIdent("LinkLuftfeuchtigkeit", $this->InstanceID);
        if ($linkID === false && $this->ReadPropertyInteger("ID-Luftfeuchtigkeit") > 0) {
            // Erstellt einen Link, wenn eine Variable / ID aus dem Objektbaum ausgewählt wurde und kein Link existiert
            $ist_luftfeuchtigkeit = IPS_CreateLink();                   // Create link
            IPS_SetName($ist_luftfeuchtigkeit, "Luftfeuchtigkeit");     // Name the link
            IPS_SetParent($ist_luftfeuchtigkeit, $this->InstanceID);    // Set a parent
            IPS_SetLinkTargetID($ist_luftfeuchtigkeit, $this->ReadPropertyInteger("ID-Luftfeuchtigkeit")); // Attach the link
            IPS_SetIdent($ist_luftfeuchtigkeit, "LinkLuftfeuchtigkeit"); // Set an identifier for the link
        }

Das brauchst du nicht, dafür hat das SDK fertige Funktionen :wink:

Michael

Das sieht doch schonmal gut aus. Ich glaube es fehlt noch die Aktualisierung des Links. Wenn also jemand später die Eigenschaft anpasst, möchtest du den Link ja wahrscheinlich nachziehen. Also, falls $linkID gesetzt ist, möchtest du trotzdem IPS_SetLinkTarget ausführen.

Was möchtest du mit der Prüfung auf ID-Luftfeuchtigkeit > 0 erreichen? Prinzipiell ist „Nichts ausgewählt“ ja 1, damit würde das nur fehlschlagen, wenn jemand gezielt die Hauptkategorie auswählt (oder falls 0 dein Standardwert ist). Falls du, wie im Kommentar dokumentiert, nur einen Link erstellen möchtest, wenn die Variable existiert, dann würde ich dir empfehlen IPS_VariableExists anstatt > 0 zu verwenden.

@Nall-chan:
Danke dir Nall-Chan, habe ich genutzt. :slight_smile:

@Dr.Niels:
Stimmt, der Code für die Aktualisierung fehlt noch. Danke dir. Habe ich ergänzt.

Damit wollte ich prüfen, ob der Link bereits vorhanden ist anhand einer vergebenen ID. Diese sind normaler weiß höher als 0. Du hast natürlich recht, das IPS_VariableExist die besser Lösung ist.

Somit sieht der Block jetzt wie folgt aus:

        $linkID = @IPS_GetObjectIDByIdent("LinkLuftfeuchtigkeit", $this->InstanceID);
        if ($linkID === false && IPS_VariableExists($this->ReadPropertyInteger("ID-Luftfeuchtigkeit"))) {
            // Erstellt einen Link, wenn eine Variable / ID aus dem Objektbaum ausgewählt wurde und kein Link existiert
            $ist_luftfeuchtigkeit = IPS_CreateLink();                   // Create link
            IPS_SetName($ist_luftfeuchtigkeit, "Luftfeuchtigkeit");     // Name the link
            IPS_SetParent($ist_luftfeuchtigkeit, $this->InstanceID);    // Set a parent
            IPS_SetLinkTargetID($ist_luftfeuchtigkeit, $this->ReadPropertyInteger("ID-Luftfeuchtigkeit")); // Attach the link
            IPS_SetIdent($ist_luftfeuchtigkeit, "LinkLuftfeuchtigkeit"); // Set an identifier for the link
        } else {
            // Aktualisiert den Link, wenn sich die ID geändert hat
            IPS_SetLinkTargetID($linkID, $this->ReadPropertyInteger("ID-Luftfeuchtigkeit"));
        }

Äh… nö

:rofl:

Und im else Zweig fehlt die Prüfung auf IPS_VariableExists
Trenn doch das Erstellung und das setzen vom Target, dann ist es vielleicht überschaubarer:

        $linkID = @$this->GetIDForIdent("LinkLuftfeuchtigkeit");
        if (!$linkID) {
            // Erstellt einen Link, wenn eine Variable / ID aus dem Objektbaum ausgewählt wurde und kein Link existiert
            $linkID = IPS_CreateLink();                   // Create link
            IPS_SetName($linkID , "Luftfeuchtigkeit");     // Name the link
            IPS_SetParent($linkID , $this->InstanceID);    // Set a parent
            IPS_SetIdent($linkID , "LinkLuftfeuchtigkeit"); // Set an identifier for the link
        }
        // Aktualisiert den Link
        $TargetId = 1; // Ungültig vorbelegen
        if (IPS_VariableExists($this->ReadPropertyInteger("ID-Luftfeuchtigkeit")) {
             $TargetId = $this->ReadPropertyInteger("ID-Luftfeuchtigkeit");
        }
        IPS_SetLinkTargetID($linkID , $TargetId); // Attach the link
       

Michael

Danke dir,
jetzt schaut es gut aus.

Das $TargetID = 1, zum ungültigen vorbelegen, funktioniert ist aber nicht so schön.

Sieht so aus beim erstellen der Instanz:
fehler_bei_instanzerstellung

Kann man mit OK bestätigen und anschließend über die Instanzkonfiguration die richtige ID auswählen die dann gesetzt wird. Nur der Instanz Name wird nachträglich nicht mehr angepasst.

Hier wäre es super, wenn es in Zukunft eine Lösung gibt, wie oben bereits angesprochen, das man kein Ziel vorgeben muss bzw. „kein Ziel gewählt“ oder ähnliches möglich ist.

Aktuell sieh es jetzt so aus, eine Mischung aus meiner bisherigen Programmierung + Input von dir.(Hier wird der Objektlink im Objektbaum erst stellt, nachdem man eine ID über die Instanzkonfiguration ausgewählt hat.)

        // Überprüfen, ob ein Link bereits existiert
        $linkID = @$this->GetIDForIdent("LinkLuftfeuchtigkeit");
        if ($linkID == false && IPS_VariableExists($this->ReadPropertyInteger("ID-Luftfeuchtigkeit"))) {
            // Erstellt einen Link, wenn eine Variable / ID aus dem Objektbaum ausgewählt wurde und kein Link existiert
            $ist_luftfeuchtigkeit = IPS_CreateLink();                                                       // Create link
            IPS_SetName($ist_luftfeuchtigkeit, "Luftfeuchtigkeit");                                         // Name the link
            IPS_SetParent($ist_luftfeuchtigkeit, $this->InstanceID);                                        // Set a parent
            IPS_SetLinkTargetID($ist_luftfeuchtigkeit, $this->ReadPropertyInteger("ID-Luftfeuchtigkeit"));  // Attach the link
            IPS_SetIdent($ist_luftfeuchtigkeit, "LinkLuftfeuchtigkeit");                                    // Set an identifier for the link
        }
     
        // Aktualisiert des Objektlinks, wenn sich die Ziel-ID geändert hat
        if ($linkID == true && IPS_VariableExists($this->ReadPropertyInteger("ID-Luftfeuchtigkeit"))) {
            IPS_SetLinkTargetID($linkID, $this->ReadPropertyInteger("ID-Luftfeuchtigkeit"));
        }