Grundsätzliche Fragen zur Modulerstellung

…ich möchte zu dem Thema noch ein Beispiel hinzufügen:
Der Nutzer hat die Möglichkeit, einen I²C-Multiplexer-Typ auszuwählen. Dabei wird
[PHP$this->RegisterPropertyInteger(„MUX“, 0);]


auf einen größeren Wert als 0 gesetzt. Das tatsächliche Vorhandensein bzw. die korrekte Funktionsweise kann ich prüfen, jedoch bei Mißerfolg den Wert aus dem Code heraus nicht wieder auf 0 zurücksetzen.
In der Praxis muss ich also nicht immer wieder nur prüfen, ob ein Multiplexer nur "wunschgemäß" vorhanden ist, sondern ob er auch tatsächlich vorhanden ist.

Ich würde es mir demnach wünschen, dass ich die RegisterProperty auch ganz "offiziell" aus dem Code heraus manipulieren kann...;)

Joachim

??
Habe ich nicht verstanden. Willst du jetzt eine Eigenschaft deregistrieren, oder was meinst du mit manipulieren?
Du kannst den Wert dich mit IPS_SetProperty auf 0 setzen, nur musst du aufpassen dass es keine Endlosschleife gibt durch das anschließende ApplyChanges.

Wenn du es eh prüfen musst (wie?, Wann ?) kannst du dir das nicht einfach in einem Buffer merken?
Michael

Hallo Michael,

deregistrieren möchte ich es definitiv nicht, nur auf einen den Tatsachen entsprechenden Stand setzen. Hier würde das bedeuten: Wird der angegebene MUX nicht gefunden, wird der Wert wieder auf 0 gesetzt.

Wie könnte das zu einer Endlosschleife kommen?

Joachim

Weil du nach IPS_SetProperty immer ein ApplyChanges ausführen musst.
Und was machst du in dieser Methode?
Prüfen ob Mux gültig und neu setzen, übernehmen.
Und prüfen neusetzen und übernehmen…
Usw…
Also aufpassen :wink:
Michael

…werde ich mich mal mit beschäftigen - insbesondere mit der potentiellen Gefahr… Danke!

In diesem Zusammenhang noch eine andere Frage:
Wie kann ich prüfen, ob eine im Konfigurationsformular eine Änderung stattgefunden hat und insbesondere wie der vorherige Wert war?
Beispiel:
Im Create():

 $this->RegisterPropertyInteger("Test", -1);

Im Konfigurationsformular kann dieser Wert verändert werden.
Ich könnte den aktuellen Wert vielleicht so „sichern“:

$OldValue = $this->ReadPropertyInteger("Test");

Und im ApplyChanges() mit

If ($OldValue <>$this->ReadPropertyInteger("Test")) { 

vergleichen.
Aber wo müsste dann das

$OldValue = $this->ReadPropertyInteger("Test");

untergebracht werden?
Vor das

parent::ApplyChanges();

in der ApplyChanges()?

Joachim

An den alten Wert kommst du nicht.
Einfach den Aktuellen Wert im ApplyChanges in einem Buffer schreiben.
Und dann im ApplyChanges den Buffer (also alter Wert) mit dem neuen aus Readproperty vergleichen.
Beim Systemstart etwas tricky, da musst du einmalig den Aktuellen Wert in den Buffer schreiben (MessageSink auf Kernelstarted).
Und im ApplyChanges aufpassen das du erst prüfst ob auch der Kernel KR_Ready ist, bevor du den alt neu Vergleich machst.

Michael

Hallo Leute,

obwohl ich nun insbesondere durch diesen Thread und die immer wieder „tapferen“ Helfer schon eine Menge gelernt hab bleiben zwei grundsätzliche Fragestellungen bisher ungelöst…

  1. 30.11.2017 19:55:48*| TimerPool*| Warte auf Beendigung des Timer-Threads…
public function Destroy() 
	{
		parent::Destroy();
		$this->SetTimerInterval("RunningTime_1", 0);
		$this->SetTimerInterval("RunningTime_2", 0);
	}

Trotz des Tipps in allen Modulen die vielleicht laufenden Timer im Destroy auf 0 zu setzen, kam es nun schon zwei Mal wieder bei Updates (und davon mache im Test einige) zu diesem Phänomen.
Gibt es hierzu noch weitere Maßnahmen um dieses auszuschließen oder zumindest (weiter) zu reduzieren?

  1. 30.11.2017 19:55:22*| InstanceManager*| Could not create instance interface:

    Warning: Kann für die Instanz #21969 das Interface nicht finden in /var/lib/symcon/modules/SymconModules/IPS2GPIO_Vaillant/module.php on line 174

Quasi bei jedem Update wird für quasi jedes Child bemägelt, dass es die SendToParent-Funktion nicht ausführen kann. In der jeweils genannten Zeile befindet sich der erste Verbindungsversuch.
Auf Vorschlag in diesem Thread testen ich das vorher jedoch mit:

private function HasActiveParent()
    	{
		$Instance = @IPS_GetInstance($this->InstanceID);
		if ($Instance['ConnectionID'] > 0)
		{
			$Parent = IPS_GetInstance($Instance['ConnectionID']);
			if ($Parent['InstanceStatus'] == 102)
			return true;
		}
        return false;
    	}      

Offenbar - so mein Verdacht - ist die ConnectionID noch gesetzt, obwohl sich auch dieses während des Update-Prozesses nicht wirklich erreichbar ist?

Vielleicht gibt es ja doch noch einen Tipp um hier und/oder dort noch eine nachhaltige Verbesserung zu erreichen?

Joachim

Zu 2) bist du sicher dass es nicht umgekehrt ist ? Also von den Parent zum Child mit SendDataToChildren ?
Oder weil noch Daten im IO ankommen?
Kann mich nicht mehr entsinnen diese Meldungen bei meinen Modulen zu sehen.
Kann mich aber auch täuschen.

Zu 1 fällt mir nix mehr ein.
Michael

Hallo Michael,

defintiv! In der oben bemängelten Zeile 174 steht folgendes:

$Result = $this->SendDataToParent(json_encode(Array("DataID"=> "{A0DAAF26-4A2D-4350-963E-CC02E74BD414}", "Function" => "set_usedpin", 
									  "Pin" => $this->ReadPropertyInteger("Pin"), "PreviousPin" => $this->GetBuffer("PreviousPin"), "InstanceID" => $this->InstanceID, "Modus" => 1, "Notify" => false)));

Beim Update-Prozess sind bei den Meldungen quasi rote Zeilen für alle aktiven Childs, jeweils die erste „Kontaktaufnahme“.

Vielleicht könnte man ja 1. und 2. insofern beheben, das im Destroy auch die Verbindung zum Parent „gekappt“ wird?

Joachim

Nachtrag: Vielleicht hilft ja auch die „Triviallösung“: Das @ vor der Zeile, würde den Fehler aber gerne „korrekt“ abfangen…

Achso, ja klar. Dann findet er das Interface im Parent nicht. Okay, dachte andersrum.
Michael

Nur weil ich es gerade gebraucht habe. Hier meine Funktion für HasActiveParent. Es prüft die ganze Kette und gibt zurück, wenn eine der Instanzen nicht Aktiv (102) ist. (Ab 5.0 wegen der IS_ACTIVE Konstante)


private function HasActiveParent()
{
    $isActive = function($id) use (&$isActive) {
        $i = IPS_GetInstance($id);
        if ($i['ConnectionID'] == 0)
            return true;
        $p = IPS_GetInstance($i['ConnectionID']);
        if ($p['InstanceStatus'] != IS_ACTIVE)
            return false;
        return $isActive($i['ConnectionID']);                  
    };

    return $isActive($this->InstanceID);
}

paresy

Mir stellt sich immer die Frage…
Sollte mein Splitter auch inactive als Status haben wenn der IO inactive ist?
Oder lasse ich den Status immer auf Active (Error jetzt Mal nicht betrachten)?

Michael

Wir lassen die Splitter immer Active, es sei denn es gibt tatsächlich einen Fehler im Splitter.

Deswegen prüfe ich auch immer die ganze Kette.

paresy

Prüfen will ich die Instanzen bis zum IO gar nicht; wenn ein Splitter in Fehler steht dann wird halt ein Fehler geworfen.
Eigentlich reicht mir da also das oberste Element, sofern es einen IO ist.
Oder spricht da etwas dagegen?
Michael

…wie kann ich ein „InstanceInterface not avaiable“ abfangen?

Im vorliegenden Fall kommt es zu einem Fehler bei einem Konfiguratorwenn dieser offen ist während des Modul-Update-Prozesses.

Im Laufe der Suche welche Instanzen schon vorhanden sind (um die Liste zu füllen) wird ein Fehler in der Zeile

$InstanceArray = (IPS_GetInstanceListByModuleID($guid));

geworfen. Ich hatte gehofft das ein

If ($this->HasActiveParent() == true) {
	$StationArray = unserialize($this->GetData());
}

dort den Aufruf dieser Funktion verhindert, dem ist aber leider nicht so…

Bekommt man dieses irgendwie anders in den Griff?

Joachim

Vermutlich nicht, nur mit @ unterdrücken und prüfen ob der Rückgabewert ungleich false ist.
Erklärung ist u.a. hier unter Punkt 1.8 zu finden:
Best Practice zur PHP-Modul Erstellung · GitHub

Michael

Hallo Michael,

der Tipp war wieder einmal gut.
Habe es jetzt so gemacht:

$InstanceArray = array();
	    	$InstanceArray = @(IPS_GetInstanceListByModuleID($guid));
	    	If (is_array($InstanceArray)) {
			foreach($InstanceArray as $Module) {....

Zumindest wurde jetzt keine Fehlermeldung mehr bei Update generiert.
Danke!

Joachim