Module werden falsch instanziert bei gleichem prefix in der jeweiligen module.json

Hallo,

Ich entwickele gerade ein Modul für Osram Lightify. Dabei stoße ich auf folgendes Problem:

Die Modulbibliothek hat zwei Module (LFYLight und LFYGroup), deren Klasse beide von der selben Basisklasse (LFYDevice) abgeleitet sind:


require_once(__DIR__ . "/../LFYDevice.php");

class LFYLight extends LFYDevice {

  public function Create() {
    parent::Create();
 
    $this->RegisterPropertyString("UniqueId", "");
    $this->RegisterPropertyInteger("LightId", 0);
    $this->RegisterPropertyString("Type", "");
    $this->RegisterPropertyInteger("LightFeatures", 0); // a combination of 1-onOff, 2-Level, 4-Color, 8-Temperatur
    $this->RegisterPropertyString("ModelName", "");
    $this->RegisterPropertyString("Manufacturer", "");
    $this->RegisterPropertyString("FirmwareVersion", "");
  }

  protected function BasePath() {
    $id = $this->ReadPropertyInteger("LightId");
    return "devices/$id";
  }

}

require_once(__DIR__ . "/../LFYDevice.php");

class LFYGroup extends LFYDevice {

  public function Create() {
    parent::Create();

    $this->RegisterPropertyInteger("GroupId", 0);
    $this->RegisterPropertyInteger("LightFeatures", 0); // a combination of 1-onOff, 2-Level, 4-Color, 8-Temperatur
  }

  protected function BasePath() {
    $id = $this->ReadPropertyInteger("GroupId");
    return "/groups/$id";
  }

}



abstract class LFYDevice extends IPSModule {

  public function __construct($InstanceID) {
    parent::__construct($InstanceID);

    IPS_LogMessage(get_class($this), 'InstanceID: '.$InstanceID.', ModuleName: '.IPS_GetInstance($InstanceID)['ModuleInfo']['ModuleName'].', Class: '.get_class($this).', ParentClass: '.get_parent_class($this));

  }

Wenn ich in der jeweiligen Modul.json beiden das gleiche Prefix gebe (‚LFY‘), dann werden die Instanzen offensichtlich falsch instanziiert. Im Logfile sieht man dann folgende Einträge:

16:07:10 | 00000 | CUSTOM | LFYGroup | InstanceID: 19836, ModuleName: LFYLight, Class: LFYGroup, ParentClass: LFYDevice
16:07:10 | 00000 | CUSTOM | LFYGroup | InstanceID: 12044, ModuleName: LFYLight, Class: LFYGroup, ParentClass: LFYDevice
16:07:10 | 00000 | CUSTOM | LFYGroup | InstanceID: 50060, ModuleName: LFYLight, Class: LFYGroup, ParentClass: LFYDevice
16:07:10 | 00000 | CUSTOM | LFYGroup | InstanceID: 46120, ModuleName: LFYGroup, Class: LFYGroup, ParentClass: LFYDevice
16:07:10 | 00000 | CUSTOM | LFYGroup | InstanceID: 12121, ModuleName: LFYGroup, Class: LFYGroup, ParentClass: LFYDevice
16:07:10 | 00000 | CUSTOM | LFYGroup | InstanceID: 24337, ModuleName: LFYGroup, Class: LFYGroup, ParentClass: LFYDevice

Vergebe ich jedoch unterschiedliche Prefixe (‚LFY‘ und ‚LFYGroup‘), dann werden die Instanzen richtig instanziiert:

16:14:05 | 00000 | CUSTOM | LFYLight | InstanceID: 45763, ModuleName: LFYLight, Class: LFYLight, ParentClass: LFYDevice
16:14:05 | 00000 | CUSTOM | LFYLight | InstanceID: 12044, ModuleName: LFYLight, Class: LFYLight, ParentClass: LFYDevice
16:14:05 | 00000 | CUSTOM | LFYLight | InstanceID: 50060, ModuleName: LFYLight, Class: LFYLight, ParentClass: LFYDevice
16:14:05 | 00000 | CUSTOM | LFYGroup | InstanceID: 20999, ModuleName: LFYGroup, Class: LFYGroup, ParentClass: LFYDevice
16:14:05 | 00000 | CUSTOM | LFYGroup | InstanceID: 48484, ModuleName: LFYGroup, Class: LFYGroup, ParentClass: LFYDevice
16:14:05 | 00000 | CUSTOM | LFYGroup | InstanceID: 24337, ModuleName: LFYGroup, Class: LFYGroup, ParentClass: LFYDevice

Gibt es da eine Erklärung für? Ich möchte gerne den gleichen Präfix verwenden, um nicht die sichtbaren Funktionen unnötig zu verdoppeln.

Gruß

Burkhard

Modules.zip (3.53 KB)

Das passiert aber nur im Konstruktor, welchen du eh nicht verwenden solltest.

Und was du nicht machen darfst ist, wenn der Prefix identisch ist, gleiche Public Methoden zu deklarieren.
Das ist ein bekanntes Problem was auch das überschreiben von IPS eigenen PHP-Funktionen betrifft.
https://www.symcon.de/forum/showthread.php?p=259984

Die Ursache siehst du, wenn du dir die__generated.php.inc anschaust.
IPS instanziert auf der Basis vom Prefix+Methodenname und somit wird die falsche Datei geladen, wenn die Namen (wie im Konstruktor) identisch sind.
Bei anderen Methoden wie z.b.ReceiveData ist mir das aber noch nie aufgefallen bzw. tritt wohl nicht auf.
Michael

Dumm, genau das hatte ich ja vor:(

Ist vielleicht eine Änderung in Sicht? Es ist sehr unschön, alle Funktionen doppelt anbieten zu müssen.

Vielleicht ließe sich etwas machen, wenn im generierten Code IPS_GetInstance($InstanceID)[‚ModuleInfo‘][‚ModuleName‘] ausgewertet würde …

Besten Dank für die schnelle Antwort

Gruß Burkhard

Funktionen musst Du ja nicht doppelt haben die kannst Du ja in eine andere Klasse auslagern.

du kannst ja ganz normal
xxx extends IPSModule
nehmen den Create Teil pro Instanz abhandelt und gemeinsame Funktionen trotzdem aus einer extra Klasse aufrufen.

So habe ich es ja auch mit der Basisklasse und den abgeleiteten Klassen gemacht. Aber es ist einfach blöd, dass dem Anwender die Methoden doppelt angeboten werden. Wie soll man das erklären?:o

Gruß

Burkhard

Wieso? Das eine ist eine Gruppe und das andere ein Gerät.
IPS kennt in dem Sinn keine Gruppen und behandelt alles als Geräte unterschiedlicher Typs.

Darf man fragen wofür die ganzen Funktionen?
Für *_GetValue gibt es doch die IPS-Variablen und GetValue.
Und was ist Applydata?
Michael

Du hast recht. Habe ich gestrichen:)

ApplyData ist eigentlich eine modulinterne Funktion, die beim Synchronisieren vom Gateway aufgerufen wird. Die habe ich nicht geschafft zu verstecken:D

Nun sind die doppelten Funktionen zwar etwas reduziert, bleiben aber doppelt:)

Burkhard

Weil das so auch nicht gedacht ist, sondern dafür der Datenaustausch genutzt werden soll.
Bitte nicht so umsetzen!
IPS kann das viel besser, als wenn du das jetzt in deinem Modul selbst zusammenbaust.
Michael

Das Problem wird endlich zur 4.3 gelöst sein. Zusätzlich auch das Problem, dass man auf falschen InstanzIDs fremde Funktionen aufrufen kann.

Beispiel:


function IOT_Send($InstanceID, $Text)
{
	if(IPS_GetInstance($InstanceID)["ModuleInfo"]["ModuleID"] == "{DE173A7A-7984-485E-9DC8-F252AFB02556}") {
		require_once('C:\IP-Symcon Debug\modules\SymconTest\IOTest\module.php');
		$result = (new IOTest($InstanceID))->Send($Text);
	}
	elseif(IPS_GetInstance($InstanceID)["ModuleInfo"]["ModuleID"] == "{DE173A7A-7984-485E-9DC8-F252AFB02557}") {
		require_once('C:\IP-Symcon Debug\modules\SymconTest\IOTestOverride\module.php');
		$result = (new IOTestOverride($InstanceID))->Send($Text);
	}
	else {
		throw new Exception("Instance does not implement this function");
	}
	return $result;
} 

Tests: SymconTest/IOTestOverride at master · paresy/SymconTest · GitHub

paresy

PS: @NallChan: Interne Funktionen können aber noch nicht überschrieben werden :wink:

Dafür gibt es einen schicken Hinweis:

16:09:22 | 00000 | WARNING | DataServer | Override of native function „HM_WriteValueInteger“ is not implemented. Module: HMSystemVariable

Top :smiley:

Schade aber auch… [emoji22]
Michael