Neuling - Einige Fragen bzgl. PHP-Modul Programmierung

Ich weiss nicht genau ab wann… Aber das prüft IPS selbst (ab 4.1?) .

Michael

Komisch, die 4.1 testing ist drauf.
Ich muss es aber abfragen, sonst kommt zu viel an, auch das was ich gar nicht dort haben will.

…ich mag mich irren, aber m.E. führt ein SendToChildren dazu dass es an allen Children gesendet wird - auch wenn man für jedes Child eine andere „implemented“-GUID verwendet hat (meine Erwartungshaltung war auch anders).

Deswegen habe ich allen Childs die gleiche „implemented“-GUID für den Datenempfang zugewiesen. Ist im ReceiveData keine entsprechende „Funktion“ vorhanden (im „Telegramm“ an die Childs sende ich einen Funktionsnamen mit), wird auch nicht verarbeitet.

Joachim

Hast du mehrere Interface-GUIDs in Verwendung?
Ich nutze intern immer die gleiche (wenn die Daten den gleichen Aufbau haben).
Zu Filtern ist es besser das zu nutzen: SetReceiveDataFilter — IP-Symcon :: Automatisierungssoftware
Michael

…nun, als Anfänder der Gitarre hatte ich erwartet - das wenn die „DataID“ eine Art „Pflichtfeld“ zu sein scheint darüber auch der Telegrammempfänger zumindest auf Instanzen mit dieser „implemented“-Guid reduziert werden. Deswegen hatte ich an anderer Stelle ja schon mal gefragt, wozu das überhaupt so sein soll, dass diese als DataID immer mitgesendet werden muss…

Jede Instanz hat aber eine eigene Instanz-id-Guid…

Joachim

Ich habe folgendes getan:

Jedes Modul hast eine GUID für die ID, implemented und parentRequirements bekommen.

In dem Splitter den ich nutze habe ich die GUIDS von den Modulen aus

parentRequirements in implemented geschrieben.

und von implemented in childRequirements geschrieben.

Die SendDataToChildren rufe ich so auf:

$this->SendDataToChildren(json_encode(Array("DataID" => "{A80ED26E-D225-480A-9ADB-0BC88A8CAEC4}", "Buffer" => $SystemInfo)));

und so:

$this->SendDataToChildren(json_encode(Array("DataID" => "{A09538DA-3DAB-4E0B-93FF-30C0E3B374D6}", "Action"=> "getRecordings", "Buffer" => $Records)));

…wobei Parents und Children ja schon definiert sind…

Der Sinn der DataID - auch wenn sie ein „Mussfeld“ ist - ist mir nicht eingängig. Zumindest habe ich festgestellt, dass - egal was ich für eine (gültige) DataID ich bei SendToChildren eingestellt habe, es bei allen im ReceiveData ankommt…

Du hast es dann „Action“ genannt, ich habe es „Function“ genannt, danach wird dann quasi unterschieden. Kommt die „Function“ im ReceiveData nicht vor, passiert in der jeweiligen Instanz auch nichts…

Joachim

Genau, aber dann verstehe ich den Sinn der DataIDs leider nicht.
Vielleicht kann uns ja jemand aufklären. :slight_smile:

Grüße,
Kai

Es gibt mehrere GUIDs.
Welche für die Interfaces und dann die der jeweiligen Module (und jede Bibliothek hat auch noch eine).
Während die der Module eindeutig sein muss, kann jedes Modul ja mehrere Interfaces haben und somit müssen diese voneinander entkoppelt sein und haben erstmal nix miteinander zu tun.
Wenn jetzt dein Splitter 4 verschiedene DataIDs zum senden an den Child nutzt, dann war es in der 4.0 so dass jeder Child alles empfing, auch wenn er nur eine DataID in der json-Datei hatte.
Darum die Prüfung im ReceiveData.
Inzwischen filtert IPS das selbstständig aus und leitet Daten nur an die korrekten Instanzen weiter.
Richtig interessant wird es wenn man dann Daten mit in IPS ab Werk verfügbaren Modulen austauschen will.
Auch dort gibt es zig Interfaces und jeder JSON-String hat dann je nach GUID einen anderen Aufbau (siehe Homematic oder HID).
Michael

Hallo Michael,

aber wie gesagt, zur Zeit läuft die 4.10 vom 26.08.
Dann dürfte es doch nicht so sein, dass er es an alle schickt. Oder wo habe ich jetzt wieder meinen Denkfehler?

Grüße,
Kai

Eigentlich nicht… Sonst zeigt mal die JSONs und den Code.
Michael

Die Jsons:

IPS_VDRRecords

{
	"id": "{8CC05593-8FC3-4DE2-8F88-2BFCC2F8177D}",
	"name": "IPS_VDRRecords",
	"type": 3,
	"vendor": "",
	"aliases":["IPS_VDRRecords"],
	"parentRequirements": ["{66900AB7-4164-4AB3-9F86-703A38CD5DA0}"],
	"childRequirements": [""],
	"implemented": ["{A09538DA-3DAB-4E0B-93FF-30C0E3B374D6}"],
	"prefix": "vdr"
}

IPS_VDRSplitter

{
	"id": "{A9EAA472-5694-49FA-8D90-1D5AC1A89915}",
	"name": "IPS_VDRSplitter",
	"type": 2,
	"vendor": "",
	"aliases":["IPS_VDRSplitter"],
	"parentRequirements": [],
	"childRequirements": ["{A09538DA-3DAB-4E0B-93FF-30C0E3B374D6}","{A80ED26E-D225-480A-9ADB-0BC88A8CAEC4}"],
	"implemented": ["{66900AB7-4164-4AB3-9F86-703A38CD5DA0}", "{ED570DC1-5103-4EBA-97D0-E3F4906DC45D}"],
	"prefix": "vdr"
}

IPS_VDRSystem

{
	"id": "{1B32A3B0-83BD-4508-A322-EAAE78AEBC42}",
	"name": "IPS_VDRSystem",
	"type": 3,
	"vendor": "",
	"aliases":["IPS_VDRSystem"],
	"parentRequirements": ["{ED570DC1-5103-4EBA-97D0-E3F4906DC45D}"],
	"childRequirements": [""],
	"implemented": ["{A80ED26E-D225-480A-9ADB-0BC88A8CAEC4}"],
	"prefix": "vdr"
}

Senden aus IPS_VDRSplitter an Childs


public function getSystemInfo() {
		$Request = new cVDRRequest($this->ReadPropertyString("host"), $this->ReadPropertyString("port"));
		$SystemInfo = $Request->get("info.json");
		$this->SendDataToChildren(json_encode(Array("DataID" => "{A80ED26E-D225-480A-9ADB-0BC88A8CAEC4}", "Action"=> "getSystemInfo", "Buffer" => $SystemInfo)));
	}

	public function getRecords() {
		$Request = new cVDRRequest($this->ReadPropertyString("host"), $this->ReadPropertyString("port"));
		$Records = $Request->get("recordings.json");
		IPS_LogMessage("RecordsReceivedSplitter", count($Records));
$this->SendDataToChildren(json_encode(Array("DataID" => "{A09538DA-3DAB-4E0B-93FF-30C0E3B374D6}", "Action"=> "getRecordings", "Buffer" => $Records)));

	}

Empfangen in IPS_VDR

  public function ReceiveData($JSONString) {
    $data = json_decode($JSONString);
    if ($data->Action == "getSystemInfo") {
      IPS_LogMessage("VDRSystem", $JSONString);
      SetValue($this->GetIDForIdent("HDD") ,$data->Buffer->diskusage->free_mb);
      SetValue($this->GetIDForIdent("FreieMinuten") ,$data->Buffer->diskusage->free_minutes);
      $ResultPlugin = "";
      foreach ($data->Buffer->vdr->plugins as $Plugin) {
        $ResultPlugin .= $Plugin->name." ".$Plugin->version."<br />";
      }
      SetValue($this->GetIDForIdent("Plugins") ,$ResultPlugin);

    }
  }
}

Empfangen in IPS_VDRRecords

  public function ReceiveData($JSONString) {

    $data = json_decode($JSONString);
    IPS_LogMessage("case",$data->Action);
    switch ($data->Action) {
      case "getRecordings":
      $Records = "<table>";
      $i = 0;
      IPS_LogMessage("VDR",utf8_decode($JSONString));
      foreach ($data->Buffer->recordings as $Record) {



        if($i % 2 == 0) {
          $Records .= '<tr style="background-color:#000000; color:#ffffff;"><td>';
        }
        else {
          $Records .= '<tr style="background-color:#080808; color:#ffffff;"><td>';
        }


        $Records .= date("d.m.Y H:i",$Record->event_start_time)." ";
        $Records .= $Record->event_title."<br /> ".str_replace("#","",$Record->event_short_text);
        $Records .= "</td><td>";
        $Records.= '<div class="button" style="border:1px solid #df0909; -webkit-border-radius: 3px; -moz-border-radius: 3px;border-radius: 3px;font-size:12px;font-family:arial, helvetica, sans-serif; padding: 10px 10px 10px 10px; text-decoration:none; display:inline-block;text-shadow: -1px -1px 0 rgba(0,0,0,0.3);font-weight:bold; color: #FFFFFF;
        background-color: #f62b2b; background-image: -webkit-gradient(linear, left top, left bottom, from(#f62b2b), to(#d20202));
        background-image: -webkit-linear-gradient(top, #f62b2b, #d20202);
        background-image: -moz-linear-gradient(top, #f62b2b, #d20202);
        background-image: -ms-linear-gradient(top, #f62b2b, #d20202);
        background-image: -o-linear-gradient(top, #f62b2b, #d20202);
        background-image: linear-gradient(to bottom, #f62b2b, #d20202);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#f62b2b, endColorstr=#d20202);"'.$this->getWebhookLink($Record->number, "Delete").'>Löschen';
        $Records.="</div> ";


        $Records.= '<div class="button" style="border:1px solid #8bcf54; -webkit-border-radius: 3px; -moz-border-radius: 3px;border-radius: 3px;font-size:12px;font-family:arial, helvetica, sans-serif; padding: 10px 10px 10px 10px; text-decoration:none; display:inline-block;text-shadow: -1px -1px 0 rgba(0,0,0,0.3);font-weight:bold; color: #FFFFFF;
        background-color: #a9db80; background-image: -webkit-gradient(linear, left top, left bottom, from(#a9db80), to(#96c56f));
        background-image: -webkit-linear-gradient(top, #a9db80, #96c56f);
        background-image: -moz-linear-gradient(top, #a9db80, #96c56f);
        background-image: -ms-linear-gradient(top, #a9db80, #96c56f);
        background-image: -o-linear-gradient(top, #a9db80, #96c56f);
        background-image: linear-gradient(to bottom, #a9db80, #96c56f);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#a9db80, endColorstr=#96c56f);"'.$this->getWebhookLink($Record->number, "Play").'>Abspielen';
        $Records.="</div><br /></td></tr>";
        $i++;



      }
      $Records.="</table>";
      SetValue($this->GetIDForIdent("AnzahlAufnahmen") ,count($data->Buffer->recordings));
      SetValue($this->GetIDForIdent("Aufnahmen") ,utf8_decode($Records));
      break;
      case "deleteRecordings":
      IPS_LogMessage("VDR", "testS");
      break;

    }
  }

Keine Angst für das ganze HTML & CSS Gedöns in der Funktion bei IPS_VDRRecords werde ich mir noch was anderes einfallen lassen.

Grüße,
Kai

Okay… verstehe ich auch nicht :smiley:
Muss paresy sich mal ansehen :stuck_out_tongue:
Allerdings habe ich dennoch eine Lösung für dich, und noch einen Tipp.

Du brauchst nicht für jede Richtung und jedes Interfaces neue GUIDs nutzen.

IPS_VDRRecords

{
	"id": "{8CC05593-8FC3-4DE2-8F88-2BFCC2F8177D}",
	"name": "IPS_VDRRecords",
	"type": 3,
	"vendor": "",
	"aliases":["IPS_VDRRecords"],
	"parentRequirements": ["{66900AB7-4164-4AB3-9F86-703A38CD5DA0}"],
	"childRequirements": [""],
	"implemented": ["{A09538DA-3DAB-4E0B-93FF-30C0E3B374D6}"],
	"prefix": "VDRRecords"
}

IPS_VDRSplitter

{
	"id": "{A9EAA472-5694-49FA-8D90-1D5AC1A89915}",
	"name": "IPS_VDRIO",
	"type": 1,
	"vendor": "",
	"aliases":["IPS_VDRIO"],
	"parentRequirements": [],
	"childRequirements": ["{A09538DA-3DAB-4E0B-93FF-30C0E3B374D6}"],
	"implemented": ["{66900AB7-4164-4AB3-9F86-703A38CD5DA0}"],
	"prefix": "VDRIO"
}

IPS_VDRSystem

{
	"id": "{1B32A3B0-83BD-4508-A322-EAAE78AEBC42}",
	"name": "IPS_VDRSystem",
	"type": 3,
	"vendor": "",
	"aliases":["IPS_VDRSystem"],
	"parentRequirements": ["{66900AB7-4164-4AB3-9F86-703A38CD5DA0}"],
	"childRequirements": [""],
	"implemented": ["{A09538DA-3DAB-4E0B-93FF-30C0E3B374D6}"],
	"prefix": "VDRSys"
}

Und das ‚filtern‘ überlässt du IPS mit SetReceiveFilter.
Dazu einfach alles was du haben willst als RegEx zusammenbauen und IPS übergeben (geht bestimmt noch eleganter… :slight_smile: )


    public function ApplyChanges()
    {

            $MyFuncs=array('getRecordings','getIrgendwas');
        
            $Lines = array();
            foreach ($MyFuncs as $Func)
            {
                $Lines[] = '.*"Action":"' . $Func. '".*';
            }
            $Line = implode('|', $Lines);
            $this->SetReceiveDataFilter("(" . $Line . ")");
            $this->SendDebug("SetFilter", "(" . $Line . ")", 0);
}

Dann hast du auch keinen Stress mehr mit den Datenaustausch an alle Devices.
Da der Aufbau der Datenpakete identisch ist, reicht ja auch eine GUID für das senden zu den Childs.

Außerdem hast du noch einen Fehler in den JSON-Files. Aktuell unterstützt IPS nicht das mehrere Module das gleiche Präfix nutzen… eventuell ist dies auch die Ursache für die Probleme mit dem Datenaustausch.

Du kannst außerdem aus deinem Splitter ein IO machen, er hat ja gar keinen Clientsocket oder einen anderen Parent :wink:
Michael

Danke Michael.
Sollte der Fehler, falls es einer ist, behoben sein. Dann müsste ich aber wieder verschiedene GUIDs nehmen, wenn ich nicht mit dem Filter arbeiten möchte, richtig?

Beim Splitter also nur den Typ ändern? Ah… ich sehe schon, du hast es angepasst. Danke.

Grüße,
Kai

Nein… warum ?
Alle deine Datenpakte sind doch immer nach den gleichen Schema… also auch das gleiche ‚Interface‘.
Eine GUID reicht dann doch.
Den Filter würde ich immer vorziehen.
Michael

PS: Ich habe allerdings selber noch ein altes Delphi Modul welches zu den Childs ca 8 Interfaces nutzt. Da war die Technik dahinter aber auch anders.

…aber helft mir mal bitte bezüglich der Sinnhaftigkeit auf die Sprünge…:confused:

Die Funktion z.B. ReceiveData wird mit dem neuen Filter nur aufgerufen, wenn ein bestimmter Schlüssel im JSON-String gefunden wird…
Aber dann wird sie doch zumindest an alle versandt? Ich prüfe auf den Schlüssel in $data->function, wenn der nicht vorkommt, dann wird auch keine Aktion ausgeführt…

Joachim

Ich vermute jetzt einfach mal, das IPS das im Hintergrund performanter macht.
Grüße,
Kai

Gesendet von iPhone mit Tapatalk

Jup…
Sonst belegt jeder Datenaustausch erstmal x-Mal Anzahl der Childs an PHP-Slots.
Es ist somit performanter und Ressourcen schonender.
Michael

Eine kurze Frage noch dazu, wenn der Filter passt und es somit in ReceiveData geht, kann ich einfach mit IF oder Switch dann die gewünschte Verarbeitung der Daten machen, richtig?

Also:


  public function ReceiveData($JSONString) {

    $data = json_decode($JSONString);
    switch ($data->Action) {
      case "getRecordings":
  #do something...
      break;
      case "deleteRecordings":
  #do something...
      break;

    }
  }

Oder gibt es da auch noch was von IPS?

Grüße,
Kai

Nicht das ich wüsste.
Würde ich auch so lösen.
Michael