PHP Modul Dataflow Generator

In IP-Symcon werden Daten zwischen einzelnen Instanzen über den Datenfluss in IP-Symcon weitergegeben. Hierbei hat jede Instanz in IP-Symcon eine eindeutige GUID (Globally Unique Identifier), anhand dessen die Instanz eindeutig erkannt werden kann. Für ein PHP Modul braucht jede Instanz eine eindeutige GUID. Innerhalb der module.json wird angegeben wie die GUID der anderen mit der Instanz kommunizierenden Instanzen lauten, damit IP-Symcon weis wohin die Daten zu senden sind. Existierende Instanzen wie TCP-, UDP-, Multicast Socket usw. haben feststehende GUID über die diese angesprochen werden. Sollte man z.B. eine eigene IO Instanz definieren, wird auch hierfür eine GUID benötigt. Der Datenaustausch zwischen IO <-> Splitter <-> Gerät erfolgt über die Funktionen ForwardData und ReceiveData, in beiden Funktionen ist jeweils die passende GUID einzutragen, damit die Funktion an die passende Instanz versendet.

Das Modul ist einfach eine kleine Hilfestellung um neue GUID zu generieren bzw. nicht versehentlich eine GUID an die falsche Stelle zu kopieren. Daher können die Vorlagen die generiert werden so übernommen werden und die GUID sind schon an der passenden Stelle eingetragen. Ich selber musste am Anfang ständig nachschauen wo denn jetzt welche GUID hingehört und außerdem die existierenden GUID für IP-Symcon Instanzen nachschlagen. Da dabei auch mal Fehler passieren können, habe ich mir irgendwann ein Skript geschrieben, das hier ist jetzt das ganze in einem Modul, eventuell ist es ja dem ein oder anderen nützlich.

Dokumentation PHP Modul Dataflow Generator

Wer Anregungen hat kann diese ja gerne loswerden, letztendlich muss man ein PHP Modul aber doch selber schreiben, die Funktion eines Moduls kann man schlecht generieren ;). Wer noch Ideen hat was man standardmäßig ergänzen kann um einen Grundgerüst für ein Modul zu haben kann gerne Vorschläge machen.

Tolle Sache, ABER du nutzt falsche Prefixe bei den Aufrufen intern, habs lokal bei mir korrigieren müssen. Dann ist es echt ne Hilfe!

Danke da schau ich noch mal rein und werde das ausbessern. Ansonsten kann man ja noch überlegen ob es Standard Methoden gibt die man doch immer in jedem Modul nutzt, dann kann man die ja auch gleich mit in eine Vorlage kopieren. Irgendwelche Ideen dazu?

Denke ich mal drüber nach.

Was mir noch aufgefallen ist, bei dem generieren Splitter template fehlt am Ende ein }, dass wird irgendwie nicht mit generiert. Habe noch nicht geschaut ob es einfach im Text den du reinschreibst fehlt.

Ich lerne aktuell noch in Sachen Modulkommunikation, da kommt mir dein Modul wie gerufen.
Bin gerade dran ein Modul für eine Pluggit Lüftungsanlage zu schreiben welche via Modbus kommuniziert - ist gar nicht so einfach :frowning:

Das habe ich noch schnell ergänzt. Kannst Du mir mal ein Beispiel geben wo die Prefixe flasch sind, habe das auf die schnelle nicht gefunden, dann kann ich das noch ausbessern.

In der FormActions() steht ein ungültiger Prefix:

protected function FormActions()
    {
        $form = '"actions":
			[
				{ "type": "Label", "label": "Generate GUIDs" },
				{ "type": "Button", "label": "Generate GUID", "onClick": "IPSPHPDataGenerator_GenerateGUID($id);" },
				{ "type": "Label", "label": "Generate scripts" },
				{ "type": "Button", "label": "Generate Scripts", "onClick": "IPSPHPDataGenerator_CreateScripts($id);" }
			],';
        return  $form;
    }

Und Analog dann auch in der form.json unter actions:

"actions":
			[
				{ "type": "Label", "label": "Generate GUID" },
				{ "type": "Button", "label": "Generate GUID", "onClick": "IPSPHPDataGenerator_getGUID($id);" },
                { "type": "Label", "label": "Generate scripts" },
                { "type": "Button", "label": "Generate GUID", "onClick": "IPSPHPDataGenerator_CreateScripts($id);" }
			],

Die Prefixe müssen „DataFlowGenerator“ heißen und nicht IPSPHPDataGenerator. Dadrunter findet er dein Modul nämlich nicht, und somit die Methoden ebenfalls nicht. Hast du vermutlich mal umbenannt und dort „vergessen“ :slight_smile:

P.S. wobei die forms.json irrelevant ist da du diese ja in der FormAction() Methode überschreibst.

Danke ist korrigiert, gute Nacht.

Klasse, Danke dir!

Guts Nächtle!

Leicht OT, aber schau Mal hier ab:
SymconBC/module.php at master · symcon/SymconBC · GitHub

Dort wird im Modul ModBus genutzt.
Anfrage und Antwort des übergeordnete ModBus Gateway findet alles mit SendDataToParent statt.
Musst ‚nur‘ die passenden Funktionen und Adressen übergeben :wink:
Michael

Finde ich gar nicht so OT. Wie ist denn in dem Fall eigentlich da die passende RX GUID und TX GUID um das ModBus Gateway anzusprechen? Das ist genau der Grund warum ich das mal in ein Skript gelegt hatte, weil es schon recht nervig ist, sich das alles irgendwo zusammen zu suchen. Dann kann ich das ja noch im dem „Generator“ als Auswahl ergänzen.

Du könntest im Prinzip die Daten auch „automatisiert“ erkennen, da die Module jeweils ihre GUIDs die Sie unterstützen oder benötigen auch angeben. Siehe hier: IPS_GetModule — IP-Symcon :: Automatisierungssoftware

Schwierig wird es die korrekte Datenstruktur zu bekommen - zumal diese nicht Dokumentiert ist und somit an der Stelle auch nicht bei Versionswechseln garantiert wird.

paresy

Dankeschön Michael, ich schaue es mir mal an!

Hi Fonzo,

I started to look into writing a module for my Aquos TV (as controlling it without is becoming quite messy) and I came across your PHP Modul Dataflow Generator and I am happy as is dose quite a bit of the needed work.

I do understand that it only creates a boilerplate for the module and I have to create the module my self but I hope you can bear with me with me asking some questions as I am new to this.

I came across what looks like an error in the code generated. The last code line (in attached code) and the comment is on the same line and this prevents the module from creating an instance in IPS (from …\AquosTV\Device Aquos TV\module.php).

public function Create()
    {
	//Never delete this line!
        parent::Create();
		
		//These lines are parsed on Symcon Startup or Instance creation
        //You cannot use variables here. Just static values.$this->ConnectParent("{24444372-B423-A3CA-7E56-C0DC54C74250}"); // Splitter}

I see that some moduls us curl and other use IO / Splitter, what are the pros and cons of using the various method?

It is slow going but quite rewarding (attempting to create a modul) and now I finally have a use for my old github account :wink:

All in all I am impressed with the modul.

Thanks

yoggi

Because every device has a special way of communication you have to add your personal code for the communication that a module works. The communication between IO / Splitter / Device GUID is used in IP-Symcon and the data flow works as described in the SDK (PHP). The idea behind the module is to make it easier to create the structure for a PHP module. You do not have to know about the GUIDs of IP-Symcon but you just have to choose which type of IO to use and then create a suitable template.

There were some errors in the generated template, so please update the module, I hope this is fixed.

Just select Client Socket und add the fields for the module you want to create like

In your special case, you need a Client socket. So your module consists of an IO and the device itself. The IO (client socket) is automatically created if you create your device. In case communication is done by a REST API you would choose own IO instead of standard io (client socket) and then you would send the data via curl from your own io.
A splitter is used if there are more then one device connected to the io. In your case, you only have your TV so there is no need for a splitter because every tv has its own IP address and a client socket for this IP address.

Until now you used a register variable and a script. In the PHP module, the data is forwarded from the client socket to your device. You get the data in ReceiveData. Data send to the IO is send via SendToIO($payload). Instead of using an action script the method RequestAction is triggered if you press a button in the web front.

Hi Fonzo,

I appreciate your help, thanks!

You say I don’t need the splitter (used with multiple IPs) but I used the „cutter“ (Type, Char cutting, Right cut chars ‚0D‘, Hex) found under splitter, is cutter not a splitter? I assume I could do the cutting with php.

With the updated Dataflow Generator modul and dynamic form I run into a problem. When I try to insert an instance of the AquosTV modul I get an error. The problem happen when

$objectid = $this->RegisterVariableBoolean('STATE', $this->Translate('State'), '~Switch', $this->_getPosition());

calls

private function _getPosition()
	{
		$this->position++;
		return $this->position;
	}

and it tries to increment position (position++).

I am not sure how/where to add this property.

I apologize for my lack of PHP and that I have to bother you for help.

yoggi

in the case if a php module is used then within the module in the method ReceiveData the data is processed. If you open the Debug Windows of the device you should see what data is send from the client socket.
Perhaps if you post the data, it is possible to help you to cut the data in the values you would need.

Oh yes this is missing.
Just add


// helper properties
private $position = 0;

in front of create


// helper properties
private $position = 0;
    
public function Create()
{

Hi Fonzo,

I am making progress but it’s slow going as I am new to IPS and PHP.

At the moment the module connects to (I am emulating the TV with Hercules SETUP utility) ip-address and port 6002 but the Client Socket needs to be added manually. Simple send and receive is also working.

Perhaps if you post the data, it is possible to help you to cut the data in the values you would need

I would gladly except your help if you have the time regarding cutting up the data!

I have added my module to my github account (git://github.com/yoggiland/AquosTV.git). At the end of “AquosTV\Device Aquos TV\module.php” I have added the protocol details but her is the short version.

Commands sent to the TV is 8-character long string ending with a carriage return (’\r’, ‚0D‘ or ‚<CR>‘). Commands are padded with blank spaces between the command and the carriage return in order to reach specified length, e.g. the Power On command ‚POWR1‘ is padded with 3 blank spaces and carriage return is added at the end (‚POWR1 \r‘). If the TV receives the command it replies OK with a carriage return at the end (‚OK0D‘) if something goes wrong ERR (‚ERR0D‘)is replied. Confirmation dose not contain information regarding what command generated the confirmation so they need to be paired up. To make sure the TV is on ‚POWR? \r‘ is sent /pulled and if the TV is on it replies 1 (‚10D‘), if off 0 (‚00D‘).

My biggest problem where I could need som help (as I have no idea how to solve this with PHP in ISP) is how to send a command and wait for the response (or time out) and group it as „one transaction“. Previously I did this with a flag, if true a command has already been sent and we need to wait for a reply. I used a cutter to process the reply, using carriage return (0D) to find the end of it and leave the rest in RegisterVariables buffer.

Thanks in advance,

yoggi

You could for example use a buffer with SetBuffer to write a value to it if a comand is send. if you receive the response via ReceiveData you can delete the value in the buffer again. To prevent that another command is send in the meanwhile until you have a response you could use semaphore IPS_Semaphore then check is the buffer is empty and then leave the semaphore again. If the buffer is not empty stay in the semaphore and wait with a while loop and prove for the empty buffer, if the buffer is empty you can leave the semaphore and send your next command.

Hi Fonzo,

I am struggling a bit as to where to store these values, as private helper properties in the object (object from class) or as a variable in the object tree or somewhere else? I also struggle a bit when it comes to use of private. Vs public vs protected functions.

Any advice would be appreciated as I am now to this.

Thanks in advance.

yoggi

If it is volatile data then this should be stored in a buffer. If there is data which indicates a condition and is necessary for the webfront then store the data in a IP Symcon varibale.

Please do not change anything that has been declared by IP-Symcon like ReceiveData these method are public.
If you create own methods you can choose. If you want a user to be able to access the method via a script or via test function from the context menu the function has to be public. If the method is public you have also to declare every parameter of the method
for example


public function Switch_TV_Channel(int $channel)

in this case you would expect the user to call the method like


AquosTV_Switch_TV_Channel(1);

or


public function Switch_TV_Channelname(string $channel)

in this case you would expect the user to call the method like


AquosTV_Switch_TV_Channelname("SVT");

Any other method that is only used by the module itself and the user don’t need access to the method should be private or protected. The user can use only methods in scripts or events in IP-Symcon that are public.