Benötige Hilfe zur sinvollen Strukturierung eines Moduls

Hallo,
bin gerade dabei ein neues Modul für den Busch-Jäger Radio Inet zu schreiben. Hier habe ich ein Problem mit der sinvollen Strukturierung des Moduls.
Als Schnittstelle dient ein UDP-Socket. Ein Splitter sollte nicht nötig sein, da es nur ein Device gibt, denke ich. Also es funktioniert zummindest so.

Wo ich jetzt ins straucheln komme ist folgendes:
Es wäre schön, wenn alles Einstellungen im Device gemacht werden könnten (sinnvoll?). Also auch die IP-Adresse. Jedoch kann ich natürlich erst mit dem Radio kommunizieren, wenn die IP-Adresse gesetzt ist. Danach kann ich z.B. die Senderliste abrufen.
Die Sender würde ich auch gerne innerhalb des Device ändern können. Also müsste man nach dem einstellen der IP-Adresse die Instanz schließen und wieder öffnen, um die Formularfelder aktuell zu haben.

Was wäre hier ein besseres vorgehen, so dass das Modul möglichst einfach einzubinden ist. Alle Einstellungen des UDP-Sockets sollen vorgegeben werden, bis auf die IP-Adresse. Diese muss man selbst eintragen.

Vielen Dank für eure Unterstützung.

Grüße
Stefan

Hallo Stefan

Ja , finde ich schon.

Das kannst du ab IPS 5.2, mit der Modul funktion : ReloadForm erledigen

Das erledigst du mit der Modul funktion : GetConfigurationForParent

Gruß Xaver

Es ist davon abhängig ob es z.B. möglich ist das Gerät im Netzwerk zu suchen und zu finden. Wenn ja macht eine Discovery Instanz Sinn, in so einem Fall müsste dann die IP nicht in die Geräte Instanz eingetragen werden.

Guten Morgen Tierfreund und Fonzo.
Vielen Dank für eure Antworten. ReloadForm ist schon mal ein perfekter Tipp.

GetConfigurationForParent habe ich schon getestet, war mir aber noch nicht ganz sicher, ob es richtig ist, weil ich beim Querlesen verschiedener Beiträge was von „nur relevant für die Anzeige, nicht für die Einstellungen“ gelesen hatte. Aber vielleicht hab ich es beim ersten lesen falsch verstanden. Schau ich mir noch mal an.

Discovery ist ja recht neu und für mich noch komplett unbekannt in der Benutzung. Das Radio / mehrere Radios kann man per Broadcast finden. Habe ich mit einem schon getestet. Aber ich wollte es mir selbst nicht zu schwer machen.
Womöglich wäre das Discovery auch nachzurüsten?

Grüße
Stefan

Ich würde die IP-Adresse nur im I/O einstellbar machen, insbesondere, da sich diese ja auch nach der ersten Erstellung üblicherweise nicht mehr weiter ändern sollte. Ansonsten hast du hier Redundanz und die beiden Instanzen müssten sich irgendwie synchron halten, was doof ist und potentiell nur Ärger macht.

GetConfigurationForParent stellt tatsächlich die Konfiguration „nur“ visuell dar. Wenn du also die Instanz erstellst, wird ja der I/O gleich mit installiert und dir wird direkt der Konfigurationsdialog vom I/O angezeigt. Hier werden deine in GetConfigurationForParent-Konfiguration vorgegeben und die entsprechenden Felder deaktiviert. Der Benutzer tippt dann also nur noch die IP ein und bestätigt die Konfiguration, inklusive der Vorgabe von GetConfigurationForParent. Würde er abbrechen, würden die Einstellungen nicht übernommen werden, aber das ist ja nicht die übliche Variante. Die Konfiguration per GetConfigurationForParent vorzugeben ist also fast gleichbedeutend mit einer harten Vorgabe.

Discovery kannst du selbstverständlich auch erst im Nachhinein einrichten. Ich halte Discovery für einen großen Mehrwert, aber erst einmal mit der Kernfunktionalität anzufangen ist sicherlich nicht unvernünftig.

Ich würde mir das discovery gerne mal anschauen, aber irgendwie bin ich blind oder suche falsch. Weder im Forum, noch in der SDK-Doku bin ich wirklich fündig geworden. Hat hier jemand einen link für mich, wo man sich einlesen kann?

Wahrscheinlich werde ich für diese Anwendung kein Discovery mit einbauen, da der Radio ja ein Doseneinbaugerät ist, welches man im Normalfall einmal einbaut und es dann gut sein lässt.

Selbst wenn man irgendwann einen weiteren verbaut, braucht man dafür kein Discovery, wie es bei Z-Wave, 1-Wire usw sinnvoll ist.

Eine Instanz vom Typ Discovery oder Konfigurator ist nur ein andere Typ in der module.json.
Die ganze Magie passiert (später) durch die Konsole und das Konfig-Element Configurator.
Den Code um Geräte im Netzwerk zu suchen und das Configurator-Element zu füllen musst du selber erstellen. Da gibt es nichts fertiges.
Allerdings gibt es inzwischen viele PHP-Module wo dieses Typen genutzt werden. Eventuell findest du dort einige Anregungen.
Vielleicht einfach mit einem Configurator-Element und fest eingetragen Werten testen wie das in der Konsole aussieht und sich verhält. Die Ideen kommen dann meistens von alleine.
Michael

hier ein kleines Beispiel zum Discover

	
function DiscoverNetwork( ){
		$timeout=2;
		$request = "M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: \"ssdp:discover\"
MX: $timeout
ST: ssdp:all
USER-AGENT: MacOSX/10.8.2 UPnP/1.1 PHP-UPnP/0.0.1a

";
		
		$local_ip_address='127.0.0.1';
	    $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
	    socket_connect($socket, '8.8.8.8', 53);  // verbinde zu UDP Adresse aber sende keine Daten
	    socket_getsockname($socket, $local_ip_address, $local_port);// somit haben wir in $local_ip_address und $local_port die Daten zum binden des Sockets
	    socket_close($socket);
		// Das eigentlich discover
		$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
		socket_bind($socket, $local_ip_address);
		socket_set_option($socket, SOL_SOCKET, SO_BROADCAST, true);
		socket_sendto($socket, $request, strlen($request), 0, '239.255.255.250', 1900);
		socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec'=>$timeout, 'usec'=>'0'));
		$read = [$socket];
		$write = $except = [];
		$name = $port = $m=null;
		$response = '';
		while (socket_select($read, $write, $except, $timeout) && $read) {
			socket_recvfrom($socket, $response, 2048, null, $name, $port);
			if(is_null($response) || !preg_match('/HTTP\/.+200 OK/',$response)) continue;
			//...
			echo $response."
";
			//...
		}
		socket_close($socket);
}

Die Angaben für den Request ect. musst du natürlich deinen Bedürfnissen anpassen , in der vorliegenden Version werden alle Upnp fähigen Geräte gefunden.

Gruß Xaver

Gerade habe ich ein anderes Problem.
Ich habe ein Formularfeld Typ Liste im Action-Bereich. Das Befüllen mir Values funktioniert.
Jetzt möchte ich hier Zeilen bearbeiten (‚onEdit‘)

Wie schaffe ich es hier, dass der Funktion Parameter übergeben werden?
Bis jetzt hatte ich nur Buttons mit

'onClick' => 'function($id)'

Die Liste befindet sich in GetConficurationForm.

Danke schon mal.

Die onEdit/Add/Delete-Funktionen der Liste funktionieren genau so wie der onClick beim Button. Du kannst also alle Konfigurationsfelder des actions-Bereich mit Namen als Variable verwenden. Also beispielsweise:


{
  "type": "List",
  "name": "MyList",
  "onEdit": "ML_MyFunction($id, $MyList)",
  ...
}

Du kannst allerdings nicht direkt auf den elements-Bereich zugreifen, da müsstest du halt die Propertys auslesen.

Irgendwas mach ich dennoch falsch.
Ich habe das aus einem anderen Modul übernommen, in dem ich mal was ähnliches gemacht habe. Die Zeile schaut aktuell so aus:

'onEdit' => 'busch_editchannel($id, $Channels[\'Name\']);',

Die Fehlermeldung ist folgende:

Die Funktion ohne Parameter kann ich aufrufen.

Das sieht eigentlich korrekt aus. Wie sieht der Header deiner editchannel-Funktion aus?

:rolleyes: Es funktioniert…

Danke Dr. Niels. Druch die Erwähnung von Header ist es mir wie Schuppen von den Augen gefallen.
Ich habe vergessen, dass die Funktionen erst mit einem reload des Dienstes übernommen werden.
Zuerst hatte ich die Funktion ohne Parameter getestet - daher der (mein) Fehler.

Gibt es hier eine Alternative ohne den Dienst neu zu starten?

Aber natürlich:)

MC_ReloadModule(int $InstanceID, string $Module);

InstanceID ist die ID des „Modul Control“,
Module ist der Name deines Moduls (Verzeichnisname)

Trick: wenn du dir die Zeile in das Schnellausführungsfenster einträgst, hast du sie schnell zur Hand …

Danke bumaas für den Tip, das ist ja wirklich sehr praktisch und erleichtert die Modulentwicklung sehr.

Aktueller Stand:
buschradio.png

Gerade bin ich am überlegen, wie ich die Senderauswahl mache. Ich könnte einen Programm+ und einen Programm- Button machen. Dann müsste man aber durch alle Sender durchschalten, um einen bestimmten Sender zu wählen (Zappen).

Wie würde sich im Webfront am sinnvollsten die Senderliste darstellen lassen, so dass man direkt auf einen Sender klicken könnte?
Es sind nur 8 Slots.

Meine Empfehlung wäre die Verwendung einer Integer-Variable. In einem von dir erstellten Profil fügst du Assoziationen für die Sender hinzu. Wenn sich die Sender später ändern, kannst du auch die Assoziationen des Profils anpassen.

Guten Morgen Dr. Niels.
Das mit der Integer Variable funktioniert wunderbar.

Wie kann ich für das Webfront einen einzelnen Button für eine Aktion des Moduls anlegen?

Dann nimmst du nur eine Assoziation 0 und in der Methode RequestAction sagst du dann, was passieren soll.

Uli

Gesendet von iPhone mit Tapatalk

Also ein Variablenprofil Integer mit einer Assoziation und Schrittweite 0. Hatte schon damit getestet, aber auf die Idee die Schrittweite auf 0 zu setzen bin ich nicht gekommen.

Das bedeutet, dass ich für 10 Buttons auch 10 Profile anlegen muss? Da gibts ja dann ein schönes Chaos in den Profilen, wenn man das öfters macht.

Alternativen gibt es dann wahrscheinlich keine, oder?

Der Hintergrund für die Buttons - vielleicht braucht man ja die auch nicht.

Ich möchte es möglich machen, dass zusätzliche URLs im Webfront eingetragen werden können (möglichst unlimitiert in der Anzahl), welche dann per Klick (Button?) an das Radio übermittelt werden.

So kann die Senderliste (8 im Radio) über das Webfront „erweitert“ werden.

Gerade denke ich über eine htmlbox nach: GET-POST-JSON-RPC-Requests-direkt-aus-HTMLBoxen-senden
Jedoch kommt mir diese Möglichkeit auch recht umständlich vor. Vielleicht gibt es noch eine sinnvollere Vorgehensweise.