Grundsätzliche Fragen zur Modulerstellung

…habe jetzt mal ein paar SendDebug eingebaut:
Gesetzter Filter (habe ihn ein bisschen gekürzt):

.*"35".*|.*"status".*|.*"get_used_i2c".*

Eine Sendung die m.E. nicht akzeptiert wird:

{"DataID":"{8D44CA24-3B35-4918-9CBD-85A28C0C8917}","Function":"get_used_i2c"}

Der Ausdruck „Function“:„get_used_i2c“ kommt m.E. genau so vor wie Du es angenommen hast, aber zumindest ja das „get_used_i2c“…
Das „|“ soll ja die ODER-Funktion darstellen, die Kombination .* das beliebige Zeichen davor und dahinter sein können?

Joachim

Ich glaube das Problem hatte ich auch erst.
Wenn man ohne ‚oder‘ arbeitet geht es wohl auch, aber mit muss der Ausdruck wohl in Klammern als capture group geschrieben werden.

Versuch es mal so:

(.*"35".*|.*"status".*|.*"get_used_i2c".*)

Michael

Guten Morgen!:slight_smile:

Ich bin schon um einiges weiter gekommen, scheitere aber manchmal an Details…
Wenn ich den Filter so setze:

$Filter = '(.*"Function":"get_usedpin".*|.*"Pin":'.$this->ReadPropertyInteger("Pin").'.*|.*"Function":"get_notifypin".*)';

wird das letzte „oder“ nicht beachtet, tausche ich die Begriffe um:

$Filter = '(.*"Function":"get_usedpin".*|.*"Function":"get_notifypin".*|.*"Pin":'.$this->ReadPropertyInteger("Pin").'.*)';

wird hier das letzte „oder“ nicht beachtet…:confused:
Möglicherweise geht nur ein „oder“??

Joachim

Hallo Joachim,

hier vielleicht mal noch eine Seite: txt2re: headache relief for programmers :: regular expression generator
Da kannst du dir auch online Reguläre Ausrücke zusammenklicken. Vielleicht hilft dir das ja auch nochmal ein wenig.

Grüße,
Kai

…den Syntax der RegEx muss man erst einmal verstehen.
Ich habe es jetzt mal so gemacht:

$Filter = '((.*"Function":"get_usedpin".*|.*"Pin":'.$this->ReadPropertyInteger("Pin").'.*)|.*"Function":"get_notifypin".*)';

(man beachte die Klammern!)
So scheint es zu funktionieren…

Joachim

…so, Dank der Trigger habe ich jetzt offenbar hinbekommen. Interessanterweise konnte ich die Geschwindigkeit des Moduls auch so weit verbessern, dass ich beim Update nicht mehr in den TimeOut-Fehler laufe!

Werde jetzt mal die Hilfsvariablen durch SetBuffer bzw GetBuffer ersetzen. Auch möchte ich noch den Start optimieren, weil das Modul da ab und zu noch einen „Anschupser“ braucht.

Was bei mir noch nicht funktioniert sind die Destroy-Funktionen. Ich sehe zwar, dass das Skript da reinläuft, kommt aber scheinbar nicht mehr dazu den Code abzuarbeiten…
Dieses wäre bei mir aber ganz gut, damit die durch die gelöschte Instanz reservierten Handle und Pin freigegeben werden können…

Joachim

…das mit den Hilfsvariablen ist abgehakt. :wink:

Versuche mich mal mit RegisterMessage…

Was ist denn die InstanzID, wenn ich wissen möchte, ob der IPS-Kernel fertig hochgeladen ist?

Joachim

Hallo Michael,

habe mal bei Dir im Kodi-Modul etwas geschaut und darauf hin es so adaptiert (Ausschnitt):

	  public function ApplyChanges()
	  {
		// Nachrichten abonnieren
		$this->RegisterMessage(0, 10103);
		$this->RegisterMessage($this->InstanceID, 10412);
		$this->RegisterMessage($this->InstanceID, 10413);
		$this->RegisterMessage($this->InstanceID, 10403);
		$this->RegisterMessage($this->InstanceID, 10503);
		$this->RegisterMessage($this->InstanceID, 10504);
		
		//Never delete this line!
		parent::ApplyChanges();
		

Warum machst Du das ApplyChanges nach den RegisterMessages?

Dann die Funktion aus der Dokumentation kopiert und eingefügt:

	public function MessageSink($TimeStamp, $SenderID, $Message, $Data)
    	{
        IPS_LogMessage("IPS2GPIO MessageSink", "Message from SenderID ".$SenderID." with Message ".$Message."
 Data: ".print_r($Data, true));


    	}

Konnte bisher keine Meldung provozieren…

Ist da jetzt irgendetwas grundsätzliches falsch?

Joachim

Moin,

hast aber schlecht abgeschaut :wink:

Schau mal hier:
Nachrichten — IP-Symcon :: Automatisierungssoftware


		// Kernel
		$this->RegisterMessage(0, 10100); // Alle Kernelmessages (10103 muss im MessageSink ausgewertet werden.)

		// Objekte (hier logischer Baum, nicht Datenfluss!)
		$this->RegisterMessage($this->InstanceID, 10412); // Untergeordnetes Objekt hinzugefügt
		$this->RegisterMessage($this->InstanceID, 10413); // Untergeordnetes Objekt entfernt
		$this->RegisterMessage($this->InstanceID, 10403); // Übergeordnetes Objekt hat sich geändert

		// Ich vermute mal das hier willst du wirklich haben: FLOWMESSAGE
		$this->RegisterMessage($this->InstanceID, 11101); // Instanz wurde verbunden (InstanceID vom Pparent)
		$this->RegisterMessage($this->InstanceID, 11102); // Instanz wurde getrennt (InstanceID vom Parent)

		// INSTANCEMESSAGE
		$this->RegisterMessage($ParentId, 10505); // Status hat sich geändert
		// (!Achtung! ParentID nutzen, ist nur verfügbar über das InstanceInterface und somit erst wenn Runlevel Ready = 10103 hat.)

Warum machst Du das ApplyChanges nach den RegisterMessages?

Je nachdem wo du nachgesehen hast (Splitter oder Device), gibt es noch eine Klasse von der ich meine ableite und die macht auch etwas im Appylchanges :slight_smile:

Michael

…abermals Dank für den Tipp!
Leider bekomme ich noch immer keine Meldungen…

Habe es jetzt hinter das Apply::Parent gesetzt…

Gibt es noch etwas anderes zu beachten? Vielleicht das so früh die InstanceID noch nicht zur Verfügung steht?

Joachim

Also wenn ich in einer Instanz dann ganz unten als übergeordnete Instanz keine einstelle, bekomme ich brav Meldungen.
Ebenso beim starten von IPS.
Michael

…habe den Satz jetzt mehrfach gelesen - aber irgendwie nicht verstanden…

Screenshot kann ich gerade nicht liefern…
Aber erzähl mal worauf genau du überwachen willst.
Michael

…das was Du da gepostet hast wäre schon ein schöner Anfang!:smiley:
(Kernelmessages und verbunden bzw. getrennten instanzen)

Zeilen 30 und 108

Joachim

Funktioniert doch:

Komisch ist nur der Eintrag Pi gefunden… ich habe gar keinen (aktiv am Netz) :slight_smile:
Außerdem hat sich dein Modul einen schon benutzten ClientSocket geschnappt.
Tausch mal ConnectParent gegen RequireParent, dann sollte er einen neuen Parent erzeugen, wenn er keinen Parent hat.

Außerdem hast du meinen Hinweis zur ParentID nicht beachtet.
So gibt es natürlich Fehlermeldungen, weil es die Variable nicht gibt.

Den Parent kannst du so ermitteln:


        $ParentID = IPS_GetInstance($this->InstanceID)['ConnectionID'];

Wie du aber im Screenshot oben siehst, sagt die IPS nicht von welchem Parent du getrennt wurdest.

Somit gibt es zwei Probleme.
Du bekommst mit Pech noch immer Nachrichten vom alten Parent (Statuschange).
Und du weißt nicht mehr welche der alte Parent war um ein UnregisterMessage durchzuführen.

Meine Lösung:
Applychanges

[ul]
[li]ParentID ermitteln
[/li][li]Alte ParentID aus einem Buffer lesen
[/li][li]Wenn unterschiedlich, Unregister auf alte ID (wenn nicht 0) und Register aus neue ID (wenn nicht 0)
[/li][li]ParentID in einem Buffer schreiben
[/li][/ul]

MessageSink:

[ul]
[li]Wenn Nachricht 11101 oder 11102
[/li][li]dann Applychanges aufrufen
[/li][/ul]

Letzeres mach ich nur weil ich faul bin…
IPS liefert beim Connect eines Parent diesen in der Nachricht mit:

01.09.2016 22:54:29*| IPS2GPIO MessageSink*| Message from SenderID 59101 with Message 11101
 Data: Array
(
    [0] => 45166
)

45166 ist der Parent welchen ich eben deinem Splitter zugeordnet habe.

Beim starten hast du auch noch viele Fehler.
InstanceInterface is not available bedeutet dass du Funktionen ausführst, welche zu diesem Zeitpunkt nicht verfügbar sind. (Hier das InstanceInterface).
Ich würde diesen Part nur ausführen wenn der Kernel ( IPS_GetKernelRunlevel() ) Ready ist.

22:57:35 | 00000 | CUSTOM  | IPS2GPIO Netzanbindung:  | Raspberry Pi gefunden
22:57:36 | 00000 | CUSTOM  | IPS2GPIO Netzanbindung:  | Port ist geschlossen!
22:57:36 | 00000 | DEBUG   | ScriptEngine         | Skript ausgeführt (Text) - Länge: 0 ~ Absender: RunScript
22:57:36 | 59101 | ERROR   | InstanceManager      | <br />
<b>Notice</b>:  Undefined variable: ParentId in <b>C:\IP-Symcon\modules\SymconModules\IPS2GPIO\module.php</b> on line <b>37</b><br />
<br />
<b>Warning</b>:  InstanceInterface is not available in <b>C:\IP-Symcon\modules\SymconModules\IPS2GPIO\module.php</b> on line <b>83</b><br />
<br />
<b>Warning</b>:  InstanceInterface is not available in <b>C:\IP-Symcon\modules\SymconModules\IPS2GPIO\module.php</b> on line <b>84</b><br />
<br />
<b>Warning</b>:  InstanceInterface is not available in <b>C:\IP-Symcon\modules\SymconModules\IPS2GPIO\module.php</b> on line <b>86</b><br />
<br />
<b>Warning</b>:  InstanceInterface is not available in <b>C:\IP-Symcon\modules\SymconModules\IPS2GPIO\module.php</b> on line <b>87</b><br />

Und hier deine Nachricht wenn der Kernel in Ready (10103) geht:

22:57:41 | 00000 | SUCCESS | Kernel               | *** IPS BETRIEBSBEREIT
22:57:41 | 00000 | DEBUG   | ScriptEngine         | Skriptausführung (Text) - Länge: 201 ~ Absender: RunScript
22:57:41 | 00000 | DEBUG   | ScriptEngine         | Skriptausführung (Text) - Länge: 197 ~ Absender: RunScript
22:57:41 | 00000 | CUSTOM  | IPS2GPIO MessageSink | Message from SenderID 0 with Message 10100

 Data: Array
(
    [0] => 10103
)

Hier dann einfach nochmal Appylchanges aufrufen… dann funzt das auch mit dem InstanceInterface :smiley:

Michael

…Danke erst einmal für Deine aufwendige Fehleranalyse!

Ist ja ein offenes Geheimnis das ich genau beim Start diese Probleme habe, deswegen ja der Ansatz mit den Messages.
Wenn sich auf die eingegebene IP etwas meldet, wird davon ausgegangen, dass es sich um einen Raspberry Pi handelt, kann aber auch noch verbessert werden.
Auf Deinen Hinweis zur ParentID hatte ich eine Funktion erstellt:

private function GetParentID()
	{
		$ParentID = (IPS_GetInstance($this->InstanceID)['ConnectionID']);  
	return $ParentID;
	}

(Zeile 743) die kommt aber vermutlich zu früh…

Wie auch immer: Ich bin dankbar für diese Hinweise und werde sie versuchen sukzessive abzuarbeiten. Leider ist für einen Anfänger die Dokumentation sehr kurz, Beispiele dort als auch im Forum sind (noch) rar…

Joachim

Hallo Michael,

leider konnte ich noch nicht alle Herausforderungen lösen.

Eine ist, das sich die Childs abmelden sollen wenn gelöscht werden.

  1. Ansatz:
        // Überschreibt die interne IPS_Destroy($id) Funktion
        public function Destroy() {
            // Diese Zeile nicht löschen.
            parent::Destroy();
            $this->SendDataToParent(json_encode(Array("DataID"=> "{A0DAAF26-4A2D-4350-963E-CC02E74BD414}", "Function" => "gpio_destroy", "Pin" => $this->ReadPropertyInteger("Pin_R"))));
            $this->SendDataToParent(json_encode(Array("DataID"=> "{A0DAAF26-4A2D-4350-963E-CC02E74BD414}", "Function" => "gpio_destroy", "Pin" => $this->ReadPropertyInteger("Pin_G"))));
            $this->SendDataToParent(json_encode(Array("DataID"=> "{A0DAAF26-4A2D-4350-963E-CC02E74BD414}", "Function" => "gpio_destroy", "Pin" => $this->ReadPropertyInteger("Pin_B"))));
       }

Irgendwie ist aber nicht genug Zeit da ich sehe das der Code nicht komplett durchlaufen wird. Muss das

parent::Destroy();

vielleicht nach dem Code kommen?

  1. Ansatz: MessageRegister
    Da habe ich das wohl vermutlich falsch verstanden, denn FM_DISCONNECT gilt wohl im Child für die Trennung vom Parent, aber nicht - wie ich angenommen habe - im Parent für die Trennung eines Childs…

Offen ist auch noch das Startproblem mit InstanceInterface is not available, aber Step-by-Step…

Wie bekomme ich die Rückmeldung, das ein Child gelöscht/getrennt wurde, ohne das dauernd zu prüfen?

Joachim

Hallo Paresy,

wäre dankbar, wenn Du Dich mal zu der Funktionsweise von „Destroy“ äußern würdest (und/oder die Dokumentation dazu etwas erweiterst) - stehe da jetzt irgendwie auf dem Schlauch…

Joachim

Destroy wird nur beim Löschen der Instanz aufgerufen. Beim Herunterfahren nicht. Dies ist definitiv ein Fehler in der Doku den wir korrigieren werden. Zeit hast du so viel, wie das PHP timelimit hergibt.

paresy

Oh das ist ja praktisch, Dann kann die zusätzliche Abfrage des Runlevel ja entfallen :slight_smile:
@Joachim:
SendToParent wartet ja auf die Antwort der ForwardData in dem Parent (dein Splitter?).
Wie soll das nach dem Disconnect funktionieren?

Zum FM_dis/Connect, Ja das bezieht sich immer auf den Parent, da es davon ja immer nur einen pro Instanz einen geben kann, jeder Parent aber x-Mal Childs.
Somit muss jeder Child die Message auswerten, kann dann aber schon SendToParent nicht mehr nutzen… Siehe oben.
Michael