FS20 Komponenten auslesen und Dokumentieren

Habe schon länger ein kleines Script für FS20 Komponenten geschrieben. Mit der Einführung von MAPPINGs erscheint es mir heute noch ein wenig wertvoller, daher stelle ich es mal hier rein.

Das Script sucht ale FS20 Devices (Aktoren) und gibt deren Adresse, OID und Location Gruppiert nach HomeCode und sortiert nach Adresse aus. Doppelt benutze Adressen haben in dieser Liste schon ein Sternchen.

Wenn eine Device ein Mapping hat (weitere Adressen), so wird das in einer Zusatzzeile ausgegeben. So kann man solche Devices schnell erkennen.

Um die Frage zu beanworten, welche Adresse wo zusätzlich benutzt wird, gibt es den Block „Mappings“, wo dies aufgelistet wird.

Schliesslich werden Dubletten in der Adresse aufgezeigt.

Anpassungen an die individuellen Wünsche bzw. den Output:

1.) Was ausgegeben wird:
$OutputParts --> dort kann angegeben werden, welche Doku gelistet wird: Nur Adressen, Mappings, Dubletten oder alles bzw. mix.

2.) Zeilenformattierung:
Für die Ausgabe habe ich Formatstrings benutzt und pintf(). So kann jeder, ohne im script selbst rumwerkeln zu müssen, die Zeilenausgabe beliebig verändern.

Alle Anpassungen im entsprechend gekennzeichneten Bereich des Scripts.

[Änderung: fehlerhaftes script ersetzt - siehe nachfolgende Diskussion]


// #########################################################################
// FS20 DEVICES INFORMATION LIST
// READS FS20 DEVICES AND LISTS THE USED ADDRESSES
//
// Ver: 2.01
// Author: JW
//
// USES: nothing
// CAVEATS:
// nicht optimales script, da doppelte Verwendung von Arrays &
// Informationen --> kann optimiert auf ein Array werden
//
// Version Information:
// Ver 2.01: fixed bug when no mappings, minor change on output
// #########################################################################

// ******************************* STANDARD HEADER ***************************
$ScriptID = $IPS_SELF; // ID of this script
$ScriptName = IPS_GetName($ScriptID);
$LogMessageIdentifier = "SCR " . $ScriptName . "[" . $ScriptID . "]";
IPS_LogMessage( $LogMessageIdentifier, "Started");
// ******************************* STANDARD HEADER END ************************

// ################# CHANGE HERE ##########################

// DEFINES WHAT OUTPUT WILL BE PRODUCED (AD=Address List // MAP=Mapping List // DBL = Doublett List
$OutputParts = "AD,MAP,DBL";

$SectionDeli = "##########################################################################
";
$SectionDeliTxtFormat = "#%-72s#
";
$NoneFoundMessage = 	"     *** NONE *** 

";

// FORMAT STRINGS USED TO DEFINE THE OUTPUT FORMATTING
$HomeCodeLineFormat = "HomeCode: %1s 
";
$HomeCodeEndLine = "
";

// LIST OF ADDRESSES WITH OID, LOCATION AND MAPPING
$AdrLineFormat = "     Adr: %-5.5s   OId: %s  Loc: %s 
";
$MapLineFormat = "                 Maps: %1s 
";
$MapDeli = " | ";
$AdrOfMapLineFormat = "    Adr: %1s is mapped at the following addresses: 
";
$AdrUsesMapLineFormat = "      --> %1s 
";

// LIST OF MULTIPLE USED ADDRESSES
$DoubleLineFirstFormat = "DOUBLE HC: %1s  ADR: %2s is used by 
";
$DoubleLineNextFormat  = "       -->  OID: %1s  Loc: %2s 
";

//################## CHANGE END ###########################

$IO_InstanceOIds = IPS_GetInstanceListByModuleType(3); // Array of OIDs of all I/O Instances



// ############################################################################
//                 PT1:  LOOP COLLECTING & FORMATTING INFORMATION
// ############################################################################
$i=1;
foreach($IO_InstanceOIds AS $OId):

   $Instance = IPS_GetInstance($OId);

   $InstanceModuleInfo = $Instance['ModuleInfo'];
   $InstanceModuleName = $InstanceModuleInfo['ModuleName'];
	if ($InstanceModuleName == "FS20"):

   	   $MyArray[$i]["Mapping"] = "";

			// GET DEVICE INFORMATION (ADRESS, HOMECODE etc)
   	   $DeviceAddress = FS20_GetDeviceAddress($OId);
      	$HomeCode = $DeviceAddress['HomeCode'];
	      $AddressGroup = $DeviceAddress['Address'];
   	   $AddressItem = $DeviceAddress['SubAddress'];
			$AddressFull = $AddressGroup . $AddressItem;
			$DeviceLocation = IPS_GetLocation($OId);

			$NewIndexKey = $HomeCode."-".$AddressFull;
			if( $i >1 ): // check only if array exists after first run
				$dbl = array_key_exists( $NewIndexKey, $AllAdrArray );
				if( $dbl ):
				   // DOUBLE USED HC / ADR COMBINATION !!!!
				   $NewIndexKey = $NewIndexKey . "*" . $i;
					$AddressFull = $AddressFull . "*" . $i;
		      endif;
			endif;
			$AllAdrArray[$NewIndexKey]["HC"] = $HomeCode;
			$AllAdrArray[$NewIndexKey]["Adr"] = $AddressFull;
			$AllAdrArray[$NewIndexKey]["OId"] = $OId;
			$AllAdrArray[$NewIndexKey]["Loc"] = $DeviceLocation;


			// STORE LOCATION AND OID
			$FS20_Infos[$HomeCode][$AddressFull]["OId"] = $OId;
			$FS20_Infos[$HomeCode][$AddressFull]["Loc"] = $DeviceLocation;

			// GET ADRESS MAPPING OF ADDITIONAL ADDRESSES FOR THE DEVICE
			$AddressMapping = $DeviceAddress['Mapping'];
  			if ( count( $AddressMapping ) >= 1):
				foreach( $AddressMapping as $Map):

				      $AddressMGroup = $Map['Address'];
			   	   $AddressMItem = $Map['SubAddress'];
						$AddressMFull = $AddressMGroup . $AddressMItem;

						$FS20_Infos[$HomeCode][$AddressFull]["MAP"][] = $AddressMFull;

					//	$MapArr[$HomeCode][$AddressMFull][0] = $AddressMFull;
						$MapArr[$HomeCode][$AddressMFull][] = $AddressFull;
				endforeach;
			endif;
			$i++;
	endif;
endforeach;




// ############################################################################
//                       PT2:  PRODUCE OUTPUT
// ############################################################################

// ----------------------------------------------------------------------------
//                         1st SECTION: ADDRESSES BY HOMECODE
// ----------------------------------------------------------------------------
$Identifier = "AD";
$do = stripos( $OutputParts, $Identifier );
if( $do===false ):
	goto MAP;
endif;

printf($SectionDeli);
printf($SectionDeliTxtFormat, "                             ADDRESSES");
printf($SectionDeli);
ksort( $FS20_Infos );
//print_r( $FS20_Infos);

// EACH HOMECODE USED WILL GIVE ONE SUBSECTION --> OUTER LOOP
$HomeCodes = array_keys( $FS20_Infos );

foreach( $HomeCodes as $HomeCode ):

   printf($HomeCodeLineFormat, $HomeCode);
	$FS20_InfosOfHomeCode = $FS20_Infos[$HomeCode];
	//print_r( $FS20_InfosOfHomeCode);

	// PRINT INFO FOR EACH ADDRESS [IN ORDER OF ADRESS BY AZ]
   ksort( $FS20_InfosOfHomeCode );
   $AddressesOfHomeCode = array_keys( $FS20_InfosOfHomeCode );
	foreach( $AddressesOfHomeCode as $Address ):
	   $FS20_InfoOfAddress = $FS20_InfosOfHomeCode[$Address];
      printf($AdrLineFormat, $Address, $FS20_InfoOfAddress["OId"], $FS20_InfoOfAddress["Loc"]);
		//print_r( $FS20_InfoOfAddress);

 	   // EACH ADDRESS MIGHT HAVE A SUBSECTION IF MAPPING, IF SO PRINT AS ONE LINE
		if ( array_key_exists( "MAP", $FS20_InfoOfAddress ) ):
			$AddressMapping = $FS20_InfoOfAddress['MAP'];
  			if ( count( $AddressMapping ) >= 1):
				foreach( $AddressMapping as $Map):
						$MapStr = $Map . $MapDeli;
				endforeach;
				$MapStr = rtrim($MapStr, $MapDeli);
		      printf($MapLineFormat, $MapStr);
			endif;
		endif;
	endforeach;
   printf($HomeCodeEndLine);
endforeach;

// ----------------------------------------------------------------------------
//              2nd SECTION: ADDRESS MAPPING REVERSED OUTPUT
// ----------------------------------------------------------------------------
MAP:
$Identifier = "MAP";
$do = stripos( $OutputParts, $Identifier );
if( $do===false ):
	goto DBL;
endif;

printf($SectionDeli);
printf($SectionDeliTxtFormat, "                              MAPPINGS");
printf($SectionDeli);
if( ! isset($MapArr ) ):
	echo $NoneFoundMessage;
	goto DBL;
endif;

ksort( $MapArr );
//print_r( $MapArr);

// EACH HOMECODE USED WILL GIVE ONE SUBSECTION --> OUTER LOOP
$HomeCodes = array_keys( $MapArr );

foreach( $HomeCodes as $HomeCode ):
	// loop for all homecodes
   printf($HomeCodeLineFormat, $HomeCode);

	// get sub-array that holds all addresses that are used as map at other devices
	$MapsOfHomeCode = $MapArr[$HomeCode];
   ksort( $MapsOfHomeCode );
	//print_r( $MapsOfHomeCode);

   $AddressesUsedAsMaps = array_keys( $MapsOfHomeCode );
	//print_r( $AddressesUsedAsMaps);

	foreach( $AddressesUsedAsMaps as $Address ):
	      // loop for each MAP address
		   printf($AdrOfMapLineFormat, $Address);
			// get sub-array that holds all addresses that use the map address
			$MappedAtAddresses = $MapsOfHomeCode[$Address];

			//	print_r( $MappedAtAddresses);
			//PRINT ONE LINE PER DEVICE THAT USES THE MAP ADDRESS
			foreach( $MappedAtAddresses as $MappedAt ):
            printf($AdrUsesMapLineFormat, $MappedAt);
			endforeach;
	endforeach;
   printf($HomeCodeEndLine);
endforeach;

// ----------------------------------------------------------------------------
//              3rd SECTION: ADDRESSES MULTIPLY USED
// ----------------------------------------------------------------------------
DBL:
$Identifier = "DBL";
$do = stripos( $OutputParts, $Identifier );
if( $do===false ):
	goto END;
endif;

printf($SectionDeli);
printf($SectionDeliTxtFormat, "                      CHECK DOUBLETTS");
printf($SectionDeli);

asort($AllAdrArray);
//print_r($AllAdrArray );
$AdrPrev = 0000;
$HomeCodePrev = 00000000;
$dblcnt=0;
$i=0;
foreach( $AllAdrArray as $Array):
	//print_r($Array);

	if( ($Array["HC"].substr($Array["Adr"],0,4) ) == ($HomeCodePrev.$AdrPrev) ):
		// double use of address
		$dblcnt++;
		$i++;
		if( $dblcnt == 1 ):
		   // first double --> print previous values
		   printf($DoubleLineFirstFormat, $HomeCodePrev, $AdrPrev, $OIdPrev, $LocPrev );
   	   printf($DoubleLineNextFormat, $OIdPrev, $LocPrev );
		endif;
	   printf($DoubleLineNextFormat, $Array["OId"], $Array["Loc"] );
	else:
	   $dblcnt=0;
	endif;
	$HomeCodePrev = $Array["HC"];
	$AdrPrev = substr($Array["Adr"],0,4);
	$OIdPrev = $Array["OId"];
	$LocPrev = $Array["Loc"];

endforeach;
if( $i = 0 ):
	echo $NoneFoundMessage;
endif;

END:


Script bringt bei mir ein paar Fehler:


Warning:  ksort() expects parameter 1 to be array, null given in C:\IP-Symcon_Ver2\scripts\Test_2.ips.php on line 176

Warning:  array_keys() expects parameter 1 to be array, null given in C:\IP-Symcon_Ver2\scripts\Test_2.ips.php on line 180

Warning:  Invalid argument supplied for foreach() in C:\IP-Symcon_Ver2\scripts\Test_2.ips.php on line 182

Ich will Dein mega Script ja nicht schmälern, aber wer nur Hauscode, Adresse und Location per Liste braucht, dafür reichen dann auch die paar Zeilen Code:


$guid = "{48FCFDC1-11A5-4309-BB0B-A0DB8042A969}";
$ids = IPS_GetInstanceListByModuleID($guid);
$adressen_fs20 = array();
foreach($ids as $id)
{
   $info = FS20_GetDeviceAddress($id);
   $adressen_fs20[] = $info['HomeCode']." ".$info['Address'].$info['SubAddress']." = ".IPS_GetLocation($id)."
";
}
sort($adressen_fs20);
echo $adressen_fs20 = implode("", $adressen_fs20);

Hi Thomas,

bei mir (IPS 2.3) läuft das script ohne Fehlermeldungen … habe es gerade auch nochmals mit dem geposteten script ausprobiert. Seltsam.

Es muss am $MapArr liegen, welches aber (NUR) in Zeile 104 definiert und gefüllt wird. Ist da vielleicht ein Kommentar bei Dir oder sowas? Was wirft denn die Zeile danach (print_r()), wenn die Auskommentierung weg ist?

Zum Scriptumfang:
Dein Script ist kürzer, das war meines in V1 auch - wesentlich kürzer.

Richtig ist natürlich: Wer einfach nur die Adressen gelistet haben will will, kann das einfache Script nutzen. Sobald man aber eine Formatierte Ausgabe möchte, Gruppierung der Ausgabe und vor allem Dubletten gekennzeichnet, wirds halt etwas aufwändiger.

Hier die Kleinigkeiten, die mein Script zusätzlich macht:
1.) Gruppierung nach Hauscode
2.) Ausgabe der Mappings je Instanz (nur, wenn vorhanden)
3.) Kennzeichnung der Doppelt benutzen Adressen
4.) Reverse-Ausgabe der Adressen, die für ein Mapping benutzt sind und wo
5.) Dublettenliste
6.) per Modifikation des Formatstrings leicht z.B. an Excel-Formate anpassbar für Doku-Zwecke
7.) Einstellbar, welche der Blöcke ausgegeben werden

Das mag man alles nicht brauchen - ich brauche es bei über 150 definierten „Aktoren“ (von denen aber nur ca. 50 echte Aktoren sind).

jwka

Ich habe die selben Fehlermeldungen wie Ferengi-Master.

Hi uwe,

ist das $MapArr gefüllt (nimm mal die Auskommentierung bei den print_r() weg --> d kann man gut nachvollziehen, bis wohin das script funzt und ab wo ein array dann wohl leer ist)?

Falls nicht, müsste „weiter oben“ ja schon ein bug sein.

Wie schon gesagt, ich kann die Fehlermeldung leider nicht produzieren - bei mir läuft’s …

jwka

ebenfalls fehler

Auch hier wieder die Frage: Kannst Du bitte verifizieren, warum das $MapArr nicht exisitiert? Denn das ist der Schlüssel zum Fehler und ich kann ihn schlicht nicht produzieren. Nur wenn ich die Zeile 104 auskommentiere, kriege ich (genau) diesen Fehler.

Das ist diese Zeile hier:

                    $MapArr[$HomeCode][$AddressMFull][] = $AddressFull;

Danke!
jwk

Hallo jwka,

ich habe den selben Fehler. Könnte es daran liegen:

Wenn eine Device ein Mapping hat (weitere Adressen), so wird das in einer Zusatzzeile ausgegeben.

das ich keine weiteren Adressen angegeben habe? Ich schalte nur ein paar Steckdosen an und aus und bin deshalb noch nicht in die Tiefen des FS20 Protokolls vorgestoßen.

Gruß

YEP! Das wars. Ich hatte natürlich meine Mappings nicht überall rausgenommen, und so war der Fehler bei mir nicht produzierbar. Aber klar, wenn keine Mappings da --> kein Array!

Habe das script oben geändert eingefügt und Vermerk geschrieben. Kannst Du bitte nochmals testen?

Danke!
jwka

Hallo jwka,

das geht.

Gruß

funzt prima !