[Draft] Best Practice zur PHP-Modul Erstellung

GUID Generator ist doch in der Doku verlinkt?!
Michael

Ich dachte da eher an so was wie eine zentrale Modulverwaltung:

  • Modul beantragen
  • GUID generieren lassen
  • Prefix generieren lassen
  • Skeleton runterladen

:wink:

Gesendet von iPad mit Tapatalk

Bei den GUID sehe ich mein Problem, bei den Prefixes schon eher …

So, endlich mal 0,5h Zeit mir auch meine Gedanken zu machen:

2.3:

Der Name/Position einer Variable darf nur über die RegisterVariable* Funktionen vorgegen werden. Nachträgliche Änderung und Sortierung obliegt vollständig dem Benutzer.

Was ist mit MaintainVariable — IP-Symcon :: Automatisierungssoftware ? Ich hoffe doch diese Funktion bleibt erhalten, da sie ja etwas universeller beim erzeugen von dynamischen Variablen ist.
Leider fehlt aber der Rückgabewert (ID der Var), bzw 0 wenn Beibehalten = false ist.

2.5

Eigenschaften (Properties) dienen zur Konfiguration durch den Benutzer. Ein Modul sollte sich niemals selber umkonfigurieren (z.B. über IPS_SetProperty oder IPS_SetConfiguration). Ebenfalls ein Aufruf aus einem Splitter Modul (siehe 5.1) ist nicht gestattet. Sollen Instanzen vorkonfiguriert erstellt werden, muss dazu ein Konfigurator erstellt werden, über den der Benutzer passende Instanzen erstellen kann.

Alles klar soweit.
Würde den Satz aber ändern auf:

Ein Modul sollte niemals andere Instanzen oder sich selber umkonfigurieren …

Nun stellen sich mir aber zwei Fragen:
1)
Was passiert wenn ich durch ein Update (egal ob IPS oder Modul) Eigenschaften aus einem alten Format in ein neues Überführen muss. Dann kann ich nur auf IPS_SetProperty zurückgreifen, oder ?
Beispiel ist das neue SelectFile. Vorher war es ein String zu einem Pfad des lokalen Dateisystems, jetzt ist der Inhalt in der Property.
2)
Was wenn ich die Daten für den IO ‚berechnen‘ muss. Zum Beispiel wird im Splitter eine typische URL eingetragen (siehe WebSocket-Modul) und diese muss zerlegt als Host + Port in den IO eingetragen werden.

3.1

Profile sollten mit PREFIX.NAME erstellt werden.

Dafür :slight_smile:
Eventuell noch der Hinweis, dass NAME aussagekräftig sein soll ?
Immer nur PREFIX.Status hilft nicht viel. PREFIX.PlayerStatus dafür schon mehr.

5.2

Es ist niemals erlaubt z.B. andere Variablen von anderen Instanzen über SetValue zu verändern.

Dann führ doch bitte $this->SetValue*(int $Ident, mixed $Value) ein :stuck_out_tongue:

Und nun ab, die Module umzuschreiben :smiley:
Immerhin habe ich dann auch noch einiges anzupassen.

Michael

Eigenschaften (Properties) dienen zur Konfiguration durch den Benutzer. Ein Modul sollte sich niemals selber umkonfigurieren (z.B. über IPS_SetProperty oder IPS_SetConfiguration). Ebenfalls ein Aufruf aus einem Splitter Modul (siehe 5.1) ist nicht gestattet. Sollen Instanzen vorkonfiguriert erstellt werden, muss dazu ein Konfigurator erstellt werden, über den der Benutzer passende Instanzen erstellen kann.

Was mache ich, wenn ich z.B. abhängig von einem Wert der Konfiguration andere Vorbelegen will? Ist das erlaubt und wenn ja, wie mache ich das, dass der Anwender es auch sieht. Konkretes Beispiel: Meine Instanz hat als eine Variable eine „SelectInstance“ und abhängig davon was er für eine Instanz ausgewählt hat sind die nachfolgenden Konfig-Parameter anders. Wie kann ich so etwas bewerkstelligen?

Warum willst du eine fremde Instanz etwas vorgeben?
Das ist das für eine Instanz und was hast du damit vor?
Aufgrund deiner Fragestellung läßt sich nicht erschließen was du erreichen möchtest.
Nicht das du eventuell auf einen ganz falschen Weg bist.
Michael

Nein, ich möchte MEINE Instanz abhängig von der gewählten anders Konfigurieren.

Ein fiktives Beispiel, weil das aktuelle zu kompliziert wäre:
Ich baue ein Modul das alle x Minuten einen Status überprüft. Wenn die gewählte Instanz ein Licht-Aktor ist, dann alle 5 Minuten, wenn es ein Rollo-Aktor ist, dann alle 10 Minuten. Das ist dann die Vorbelegung, der Anwender könnte den Wert aber in der Konfig überschreiben.

Klingt jetzt etwas komisch , aber ist nur ein Beispiel

Woran willst du festmachen dass der User den Wert geändert hat um nicht ausversehen seine Einstellung zu überschreiben?
Da du die Hoheit des Users wahren sollst, empfehle ich es gar nicht automatisch zu ändern.
Michael

Na ich belege den Wert bei der Auswahl der Instanz vor und lasse ihn bis zu einem eventuellem Wechsel „in Ruhe“. Aber darum geht es ja eigentlich nicht wirklich oder? Sondern ob es möglich ist… ich habe noch keinen Weg gefunden, denn IPS_SetConfiguration funktioniert zumindest nicht wie erwartet.

Wie vom Programmablauf willst du erkennen ob der User jetzt den Wert oder die Instanz geändert hat?
Gib einfach x Minuten vor und fertig.
Michael

Geht es denn oder nicht… wir brauchen uns ja jetzt nicht um ein fiktives Beispiel streiten, es gibt aber valide Anwendungsfälle dafür.

Wenn du meinst.
Ich habe und kenne keine Anwendungsfälle.
Gehen wird theoretisch alles, allerdings eher aufwendig.
Einen Lösungsvorschlag kann ich dir nicht unterbreiten da es einfach nicht dem BestPractice entspricht.

Michael

So ein ähnliches Problem habe ich aber durchaus auch. In einem Konfigurator werden Dinge von extern einmailg importiert und dann als Properties abgelegt. Da ist schon mal der erste wacklige Punkt das man nicht Set Property benutzten soll aber es dann für einen Konfigurartor doch wieder Ausnahmen gibt. Variablen kommen nicht in Frage da sprenge ich den Variablen Vorrat von manchem Nutzer von IPS. Buffer geht auch nicht denn dann müsste der Nutzer jedes mal bei einem Neustart den Import neu durchführen. Also so eine richtige Lösung habe ich auch noch nicht gefunden. So was wie zusätzliche interne Variablen die nicht zum IPS Variablen Vorrat zählen wäre daher vielleicht doch nicht schlecht. Ansonsten bin ich aber auch für jeden anderen Lösungvorschlag offen.

Gibt es auch nicht.
Da steht doch nur das so etwas über einen Konfigurator gelöst werden sollte.
Dieser kann über ein Inline-Script über einen Button im Aktions-Bereich die Instanz erstellen und alle Eigenschaft setzen.
Da dieses Script durch die Console ausgeführt wird, und nicht in deiner Modul-Klasse ist es konform.
Sieht nur etwas doof aus im JSON:


{
            "type": "Button",
            "label": "Create",
            "onClick": "if (($devices['UUID'] == '') or ($devices['instanceID'] > 0)) return; $InstanceID = IPS_CreateInstance('{BDA62C9C-EBCB-4AFB-878B-5108EE5CF012}'); if (IPS_GetInstance($InstanceID)['ConnectionID'] != IPS_GetInstance($id)['ConnectionID']) { if (IPS_GetInstance($InstanceID)['ConnectionID'] > 0) IPS_DisconnectInstance($InstanceID); IPS_ConnectInstance($InstanceID, IPS_GetInstance($id)['ConnectionID']); } @IPS_SetProperty($InstanceID, 'UUID', $devices['UUID']); @IPS_ApplyChanges($InstanceID); IPS_SetName($InstanceID, 'My new Sensor'); IPS_ApplyChanges($id);"
        }

Man kann auch andere Dateien außer ein PHP-Script innerhalb eines ‚Script-Objektes‘ in IPS speichern.
So macht es glaube ich auch die IPS-Library.
Anstatt PHP-Code einfach Text, JSON oder sonstwas da drinnen hinterlegen (CSV für meine Telefonbücher…mhhh das ist mal eine Idee :slight_smile: )

Michael

Letztendlich verstanden habe ich das jetzt trotzdem noch nicht ganz was da jetzt der Unterschied ist bzw. was da der Vorteil ist. Weil da wird doch jetzt auch nichts anderes gemacht als IPS_SetProperty und IPS_ApplyChanges. Wenn im Konfigurator z.B. ein Haken gesetzt wird und ich dann den gleichen Code ausführe wenn der Haken gesetzt ist wo ist jetzt da genau der Unterschied bzw. was für einen Vorteil hat dies das als Button mit Onclick zu machen?

Der Unterschied ist wer das Script ausführt.
Deine Funktion in deinem Modul (nicht erlaubt) oder die Console (nicht verboten :wink: ).
Außerdem hilft es eventuelle Schleifen (wenn es jetzt sich selbst konfigurieren würde) zu vermeiden.
Michael

Habe noch mal etwas überlegt und es gibt eine Lösung wie es vielleicht für den User noch besser erkennbar ist was passiert und du von ihm möchtest, wenn du einen Wert vorbelegst.

Am Beispiel deiner Minuten geht z.B. folgendes.

Eine Eigenschaft ‚Timer‘ (Die Minuten vom User eingestellt) mit Wert -1 registrieren.

In GetConfigurationForm gibst du ein Label mit zurück welches als Text deine ‚Vorgabe‘ darstellt.
z.B: Der vorgegebene Wert ist 5 Minuten, bitte ändern sie nachfolgenden Wert nur bei Bedarf.

Im Applychanges prüfst du nun ob die Eigenschaft ‚Timer‘ -1 ist => Dann deine errechnete Vorgabe nutzen.
Wenn 0, dann hat der User halt deaktiviert.
Wenn größer 0 dann den Wert vom ‚Timer‘ im Modul nutzen.

Das Ergebnis schreibst in einen Buffer und kannst dann immer damit arbeiten bzw. ohne erneut zu prüfen wieder auslesen.

Michael

Mal von der Lösung als solches ab… wie könnte ich denn das von die beschrieben „Variable“ Label definieren?
Da müsste der Wert ja im Label stehen, gesehen habe ich das jetzt noch nicht… einfach den Wert mit dem festen Teil per String-Verknüpfung in der form.json?

GetConfigurationForm
GetConfigurationForm — IP-Symcon :: Automatisierungssoftware
Oder Mal in Paresys Testmodule nachschauen.
Z.B. SymconTest/module.php at master · paresy/SymconTest · GitHub
Michael

OK, das hatte ich befürchtet… hatte gehofft es gibt einen einfacheren Weg :smiley: