Grundsätzliche Fragen zur Modulerstellung

Hallo Paresy,

ich habe nur 10803 „abonniert“ und bekomme ohne Änderung (nur Wochenplan öffnen und mit okay wieder schließen ca. 50 Meldungen…

Joachim

…noch eine „kleine“ Herausforderung…:mad:

Eines meiner Modulemacht beim ersten Start eine Fehlermeldung die ich deuten kann:

Warnung: Objekt mit Ident IPS2SRC_Event_49785 (Ident vom Wochenplan) wurde nicht gefunden. …ipsmodule.inc.php on line 38

Die Instanz bekommt keinen Namen und wird nicht dort „einsortiert“ wo sie eigentlich hin sollte. Wenn ich sie dann aufrufe und mit „Übernehmen“ die Einstellungen vornehme gibt es keine weitere Fehlermeldung und das Modul scheint fehlerfrei zu funktionieren…:confused:

In den letzten Stunden habe ich versucht herauszufinden, wo das Modul versucht den Wochenplan aufzurufen bevor es vollständige Initialisiert wurde - ich finde den Fehler einfach nicht…:mad:

Der Wochenplan scheint auch vollständig und korrekt angelegt zu werden…

Worauf lässt die Fehlermeldung schließen?

Joachim

Das du irgendwo im create oder ersten Aufruf von ApplyChanges versuchst auf das Objekt zuzugreifen, obwohl es nicht vorhanden ist.
Vielleicht einfach das @ vor $this->GetIDForIdent vergessen?
Michael

Hallo Michael,

überall wo dieser Ident aufgerufen wird hatte ich jetzt schon eine Prüfung programmiert, ob das Event überhaupt existiert - keine Änderung, obwohl ich meine das diese Teile des Skriptes noch gar nicht durchlaufen werden…
Habe jetzt noch mal überall das @ vor Zeilen gemacht, bei denen dieser Ident verwendet wird - ohne Erfolg.

Ich befürchte es ist wieder so etwas wie Leerzeichen oder ähnliches, aber auch das habe ich meine ich schon überall geprüft…:frowning:

Joachim

Hier dein Fehler:


	private function RegisterEvent($Name, $Ident, $Typ, $Parent, $Position)
	{
		if (!IPS_EventExists($this->GetIDForIdent($Ident)))
	        {
	            	$EventID = IPS_CreateEvent($Typ);
			IPS_SetParent($EventID, $Parent);
			IPS_SetIdent($EventID, $Ident);
			IPS_SetName($EventID, $Name);
			IPS_SetPosition($EventID, $Position);
			IPS_SetEventActive($EventID, true);  
			// Initiale Befüllung
			
	        }
		
	}

Wenn du ein neues Event damit erstellst, dann willst du mit IPS_EventExists prüfen ob es überhaupt existiert.
Leider tut es das ja beim ersten Aufruf nicht und das ermitteln der ID schlägt fehl: $this->GetIDForIdent($Ident) => Fehler.

Wie man richtig machst steht in der __ipsmodule.php

Beispiel:


		protected function RegisterTimer($Ident, $Milliseconds, $Action) {

			//search for already available scripts with proper ident
			$eid = @$this->GetIDForIdent($Ident);

			//properly update eventID
			if($eid === false) {
				$eid = 0;
			} else if(IPS_GetEvent($eid)['EventType'] <> 1) {
				IPS_DeleteEvent($eid);
				$eid = 0;
			}
.			//we need to create one
			if ($eid == 0) {
				$eid = IPS_CreateEvent(1);
				IPS_SetParent($eid, $this->InstanceID);
				IPS_SetIdent($eid, $Ident);
				IPS_SetName($eid, $Ident);
				IPS_SetHidden($eid, true);
				IPS_SetEventScript($eid, $Action);
			} else {

.
.
.
.
.

Dass für deine Mehtode umgesetzt:


	private function RegisterEvent($Name, $Ident, $Typ, $Parent, $Position)
	{
		$eid = @$this->GetIDForIdent($Ident)
		if($eid === false) {
			$eid = 0;
		} else if(IPS_GetEvent($eid)['EventType'] <> $Typ) {
			IPS_DeleteEvent($eid);
			$eid = 0;
		}
		//we need to create one
		if ($eid == 0) 
	        {
	            	$EventID = IPS_CreateEvent($Typ);
			IPS_SetParent($EventID, $Parent);
			IPS_SetIdent($EventID, $Ident);
			IPS_SetName($EventID, $Name);
			IPS_SetPosition($EventID, $Position);
			IPS_SetEventActive($EventID, true);  
			// Initiale Befüllung
	        }
		
	}

Michael

Danke, danke, danke!!!:d

Hallo Leute,

wenn man das Konfigurationsformular dynamisch erzeugt und man dort Checkboxen erzeugt braucht man ja doch eingentlich auch das entsprechende „Gegenstück“ von RegisterPropertyBoolean in der Create Methode.

Wenn ich die maximale Anzahl kenne wäre das ja keine Herausforderung, was aber wenn ich diese nicht kenne?

Kann ich „situativ“ auch die Create Methode ebenso nachträglich anpassen?

Ein kleines Beispiel:
Es können n Sensoren angeschlossen werden. Das Modul ermittelt die aktuell angeschlossene Anzahl und zeigt diese dynamisch erstellt im Konfigurationsformular der Instanz an. Der Nutzer soll nun per Checkbox auswählen können, bei welchen Sensoren die Daten mitgeloggt werden sollen. Nun müsste ich ja das oben schon erwähnte „Gegenstück“ auch in der Create Methode mit RegisterPropertyBoolean anlegen…

Oder mache ich da einen Denkfehler?

Joachim

Keine Ahnung was das soll (Logging hat ja in Instanzen so nix zu suchen, da die Handhabung zu anderen Variablen dann abweicht).
Aber was meist du mit Gegenstück?
UnregisterProperty ?
Schreib die Konfig doch einfach komplett als JSON in einen String. Somit hast du eine Dynamik.
Michael

War vielleicht ein unpassendes Beispiel…

Mit „Gegenstück“ meine ich, dass ich für eine Checkbox im Konfigurationsformular eine Boolean-Proberty in der Create-Methode brauche um die Einstellung des Users zu sichern und im Code nutzen zu können.

Anderes Beispiel: ich möchte zu jeden gefundenen Sensor einen Korrekturfaktor im Konfigurationsformular eingeben lassen können, nur weiß ich halt nicht wie viele es am Ende wirklich werden…

Joachim

Stimmt IPS überführt dies ja direkt in die Settings.
Wobei ich mich da jetzt Frage, ob dafür jetzt die Dynamik in den Formularen gedacht ist.
Ich hätte einfach pro Sensor eine Instanz angelegt.
Alternativ hast du später die Listen, mit denen geht das dann auch.
Michael

…ja, habe ich ja bei allen anderen auch gemacht (auch wenn einiges nicht wirklich 1:n ist).
Habe mich mal an die dynamischen Formulare getraut und so überlegt, was man denn so tolles damit machen kann.
Das was ich jetzt „zur Übung“ mal umgestellt habe (von der Form.json auf getconfiguation) ist das 1-Wire Modul. Dort ist es so, dass der Raspberry Pi das sowieso auf 10 Sensoren begrenzt, führte aber zu der Fragestellung (ich könnte also einfach 10 Probertys ablegen und die dann nutzen) Das Beispiel war konstruiert!
Aber: Im Ergebnis heisst das doch, ich könnte zwar im Formular n-Eigenschaften erzeugen, aber nicht dazu die Probertys?

Joachim

Genau.
Du musst immer alle erzeugen, kannst aber weniger anzeigen.
Michael

Ich lasse z.B. so viele Eigenschaften erzeugen wie z.B. Geräte angegeben sind ob das auch eleganter geht weis ich nicht schau mal z.B. ins Flow Modul.

Ich habe das bei mir eingeschränkt auch mit einem Hinweis im Modul Du musst die Eigenschaften ja erzeugen also n max z.B. 300 erzeugst Du 300 Eigenschaften. Die musst Du ja nicht anzeigen im Formular wenn diese nicht benötigt werden da sind die aber trotzdem. Wenn sich jetzt rausstellt das doch 350 benötigt werden dann müsstest Du das dann halt nachträglich noch ändern.

Hallo Fonzo,

das Beispiel war vielleicht ungünstig gewählt, dass es auch andere Möglichkeiten gibt ist mir klar - nur „sauber“ erscheinen die mir nicht, denn jede (Deiner 300) Property kann ja dann auch per Set-Befehl angesprochen werden.

Ob man dem Nutzer die Option schaffen sollte das Logging schon in der Modul-Instanz aktivieren zu können ist dagegen wieder eine Frage, die man gerne unter „Grundsätze der Modulerstellung“ zusammenfassen sollte. Mein Bestreben ist doch, ein Modul möglichst „regelkonform“ zu erstellen deswegen würde ich die Erstellung eines solchen Leitfadens als auch die Qualitätskontrolle sehr befürworten…

Joachim

Ja „sauber“ ist das nicht, aber so eine richtige Idee wie man das anderes lösen soll wenn ich in einem Dynamischen Formular nicht weis was kommt habe ich auch nicht. Ob das ein Problem darstellt wenn ich die alle einzeln ansprechen kann weis ich nicht ich konnte da noch nichts beobachten, zumindest verbrauchst Du so nicht unnütze Variablen. Und zum Thema Leitfaden zur Modulerstellung stimme ich Dir hundert Prozent zu, das müsste nur mal einer von IP-Symcon schreiben wenn Zeit ist ;).

…andere Frage:
Paresy hat wie ich finde eine strukturierte Art der dynamischen Formularerstellung in einem seiner Beispiele:

public function GetConfigurationForm() {
		
		$arrayElements = array();
		$arrayElements[] = array("name" => "SourceVariable", "type" => "SelectVariable", "caption" => "Source");
		$arrayElements[] = array("name" => "Border0", "type" => "NumberSpinner", "caption" => "Border 0", "digits" => 4);
		
		for ($i = 1; $i <= self::BORDERCOUNT; $i++) {
			$arrayElements[] = array("name" => "Formula".$i, "type" => "ValidationTextBox", "caption" => "Formula ".$i);
			$arrayElements[] = array("name" => "Border".$i, "type" => "NumberSpinner", "caption" => "Border ".$i, "digits" => 4);
		}
		
		$arrayActions = array();
		$arrayActions[] = array("name" => "Value", "type" => "ValidationTextBox", "caption" => "Value");
		$arrayActions[] = array("type" => "Button", "label" => "Calculate", "onClick" => "echo UMG_Calculate(\$id, \$Value);");
		
		return JSON_encode(array("elements" => $arrayElements, "actions" => $arrayActions));
	
	}

Wie würde nach dieser Struktur ein „Select“ aussehen? Insbesondere meine ich die einzelnen „Options“?

Joachim

…der Anfang wäre doch sicherlich so:

$arrayElements[] = array("type" => "Select", "name" => "Pin", "caption" => "GPIO-Nr.", "options" => ... );

…die Options selbst:

"label" => "0", "value" => 0,

aber wie bringt man das zusammen?:confused:

Baut man die Options selbst als Array auf und fügt dieses dann den $arrayElements hinter „options“ => zu?

Joachim

…oder mal „gespielt“, ergibt dieses:

$arrayOptions = array();
		$arrayOptions[] = array("label" => "ungesetzt", "value" => -1);
		for ($i = 0; $i < 27; $i++) {
			$arrayOptions[] = array("label" => $i, "value" => $i);
		}
		$arrayElements[] = array("type" => "Select", "name" => "Pin", "caption" => "GPIO-Nr.", "options" => $arrayOptions );

etwas was dem entspricht?

       { "type": "Select", "name": "Pin", "caption": "GPIO-Nr.",
            "options": [
                { "label": "ungesetzt", "value": -1 },
                { "label": "0", "value": 0 },
                { "label": "1", "value": 1 },
                { "label": "2", "value": 2 },
                { "label": "3", "value": 3 },
                { "label": "4", "value": 4 },
                { "label": "5", "value": 5 },
                { "label": "6", "value": 6 },
                { "label": "7", "value": 7 },
                { "label": "8", "value": 8 },
                { "label": "9", "value": 9 },
                { "label": "10", "value": 10 },
                { "label": "11", "value": 11 },
                { "label": "12", "value": 12 },
                { "label": "13", "value": 13 },
                { "label": "14", "value": 14 },
                { "label": "15", "value": 15 },
                { "label": "16", "value": 16 },
                { "label": "17", "value": 17 },
                { "label": "18", "value": 18 },
                { "label": "19", "value": 19 },
                { "label": "20", "value": 20 },
                { "label": "21", "value": 21 },
                { "label": "22", "value": 22 },
                { "label": "23", "value": 23 },
                { "label": "24", "value": 24 },
                { "label": "25", "value": 25 },
                { "label": "26", "value": 26 },
                { "label": "27", "value": 27 }
                ]
        }

Joachim

…der Syntax für das „Select“ ist offenbar so korrekt.

Hier aber noch mal eine andere Herausforderung:

$arrayActions[] = array("type" => "HorizontalSlider", "name" => "Slider", "minimum" => 0,  "maximum" => 255, "onChange" => "I2GDMR_Set_Intensity(".$this->InstanceID.", $Slider);");

Wie muss die Variable „$Slider“ bestimmt werden?

Joachim