Umgang mit Registervariablen

Ich habe mich ein bischen mit RegisterVariablen auseinandergesetzt und rumprobiert. Bei mir ist es der Fall, dass ich innerhalb eines vom Benutzer ausgelösten Scriptes mehrere „Calls“ nacheinander absetze (z.B. via ClientSocket) und die zurückgegebenen Ergebnisse dann auswerten will. Das ist m.e. nicht ganz so einfach, weil man ja warten muss, bis die Response da ist und das innerhalb des Scripts nicht mitbekommt (? ist das so oder gibt’s nen Trick?).

Damit keine zurückgelieferten Werte verloren gehen, muss man sich einen eigenen „Heap“ basteln, und diesen dann abarbeiten.

Damit RegisterVariablen „in aller Ruhe“ oder auch zu einem späteren Zeitpunkt ausgewertet werden können (z.B. in einem Batch-Run) habe ich ein kleines PHP geschrieben, welches eine (beliebige) RegisterVariable ausliest und deren gelieferten Wert dann in eine verkettet Liste schreibt. Der Aufbau dieserListe ist:
<delimiter><Wert 1><delimiter><Wert 2><delimiter> … <delimiter><Wert n)

Damit das script möglichst universell benutzt werden kann (sozusagen als „standard-event bei Registervariablen“ ist noch eine Parameter-Variable hinzugekommen … dazu gleich mehr.

Ohne jegliche weitere Anpassung legt das Script eine Buffervariable an. Sie ist „Child“ der Registervariable und hat den Namen der RegisterVariable plus Erweiterung „.Buffer“. Diese Buffervariable wird dann mit den Werten der Registervariablen gefüllt, als Trennzeichen wird das „^“ verwendet und die maximale Anzahl Werte ist 20. Alles wird natürlich als String gespeichert.

Wem das nicht passt, der kann die Buffervariable selbst anlegen (Namenskonvention ist allerdings wie oben) und dann weine weitere Variable als Child unter der Buffervariablen anlegen, die „Parameters“ heisst. Der Inhalt miss dann ein Text sein, der wie folgt interpretiert wird: erstes Zeichen ist der Trenner für einzelne Werte (so kann ein anderes Zeichen als „^“ verwendet werden) und die folgenden Zeichen (bis max. 5) werden als Integer interpretiert und stellen die maximale Länge der Liste dar.

Wer also z.B. „#“ als Trenner und nur 5 Zeilen möchte, der trägt dort ein: „#5“.


/* ***************************************************************************
GLOBAL SCRIPT TO HANDLE REGISTER VARIABLES AND PURGE CONTENT INTO BUFFERS

reads Register variable and writes new received values into Buffer variable.
 - if Buffer var does not exist, creates it
 - if Buffer var exists, appends values just received
 - WITHOUT child variable named "Parameters"
 - - max. 20 lines are retained, rest is cut
 - - default delimiter is ^
 - WITH child variable named "Parameters"
 - - format shall be <1 digit delimiter><1-5 digit number> i.e.: ".10"
 - - first char is interpreted as maxlines (i.e. ".")
 - - second to 5th char is interpreted as number of lines (i.e. 10)
 
TO BE DONE:
	semaphore to prevent crash if quick calls on same register variable

V 0.1
author: jw
last change: n/v
*************************************************************************** */

// help to allow to test this script from editor
if ($IPS_SENDER == 'Execute'):
	$RegVarID = 21212;
	$RegVarValue = date('Y.m.d H:m:s');
else:
	$RegVarID = $IPS_INSTANCE;
	if (is_string($IPS_VALUE)):
		$RegVarValue = rawurldecode( rtrim($IPS_VALUE, "\x0D" ) );
	else:
	   $RegVarValue = strval($IPS_VALUE);
	endif;
endif;
// ######################## CHANGE VALUES HERE ##############################
$BufferLinesDelimiter = "^";
$BufferLinesMax = 20; // max values kept in buffer
$BufferLinesMax = 3; //
$RegVarBufferNameExt = '.Buffer';
$RegVarBufferParametersName = 'Parameters';
// ##################### NO CHANGE BEHIND THIS LINE #########################

$RegVarObject = IPS_GetObject( $RegVarID );
$RegVarName = $RegVarObject['ObjectName'];
$RegVarBufferName = $RegVarName . $RegVarBufferNameExt;
$RegVarBufferID = @IPS_GetVariableIDByName( $RegVarBufferName , $RegVarID );

if ( $RegVarBufferID === false ) :
	// buffer variable does not exist --> create [ALLWAYS STRING !!]
	$RegVarBufferID = IPS_CreateVariable( 3 );
	IPS_SetParent( $RegVarBufferID, $RegVarID );
	IPS_SetName( $RegVarBufferID, $RegVarBufferName);
else:
	// buffer exists, read first [timing] and append actual buffer value to existing buffer lines
	$RegVarBufferVal = GetValue( $RegVarBufferID );

	// now, look if parameters are supplied
	$RegVarBufferParametersID = @IPS_GetVariableIDByName( $RegVarBufferParametersName , $RegVarBufferID );
	if ( ! ( $RegVarBufferParametersID === false ) ) :
		// read parameters defined
		$Parameters = GetValueString( $RegVarBufferParametersID );
		if ( $Parameters <> "" ) :
			$Delimiter = substr($Parameters,0,1);
         $NewBufferLinesMax = intval(substr($Parameters,1,5));
         if ( $Delimiter <> "" ) :
	         $BufferLinesDelimiter = $Delimiter;
			endif;
			if ( $NewBufferLinesMax > 0 ):
				$BufferLinesMax = $NewBufferLinesMax;
			endif;
		endif;
	endif;
endif;

// NOW APPEND THE NEW VALUES, CUT TO APPROPRIATE LENGHT, WRITE TO BUFFER VARIABLE
$Delimiter = substr($RegVarBufferVal,0,1);
$BufferLinesARR = explode($Delimiter, $RegVarBufferVal);
array_shift($BufferLinesARR); // 1st empty due to delimiter in list = 1st char
$BufferLinesARR[] = $RegVarValue; // APPEND ACTUAL
$BufferLinesCount = count($BufferLinesARR);
$BufferLinesARR = array_slice($BufferLinesARR, -$BufferLinesMax);
$RegVarBufferVal = $BufferLinesDelimiter . implode( $BufferLinesDelimiter, $BufferLinesARR);

SetValue( $RegVarBufferID, $RegVarBufferVal);



Der Zugriff auf Werte erfolgt dann wie folgt:

  • auslesen der BufferVariable
  • $delimiter=substr( $var, 0, 1);
  • $array = explode( $delimiter, $var);

Das erste Arr-Element ist dann natürlich leer, was hilft „menschlicher“ zu zählen (Start von Index=1). Wer’s klassisch haben will, nutzt noch zusätzlich
array_shift($array)

jwka

Ich möchte dich ja ungern bremsen… aber du hat den FETTEN HINWEIS in der Dokumentation einfach ignoriert. Einfach so. Warum!?

Hier noch einmal:

Verwenden Sie bitte KEINE VARIABLE als Puffer. Andernfalls kann es zu Instabilitäten innerhalb von IP-Symcon kommen und im schlimmsten Fall eine komplett zerstörte Konfiguration verursachen. Da dieses Problem sich auch inkrementell auf den Backup Ordner auswirken kann, haben Sie dann unter Umständen nicht einmal ein Backup Konfiguration.
Nutzen Sie den internen Puffer der Instanz, um Daten zwischenzuspeichern.
RegVar_SetBuffer / RegVar_GetBuffer

RegisterVariable: IP-Symcon :: Automatisierungssoftware

Ähhhm: Den Hinweis habe ich schon GELESEN. Aber wohöl nicht verstanden.

Ich habe ihn NICHTso verstanden, dass man GENERELL nix in Variablen Puffern soll - oder ist das etwa so???

Wozu bitte sollten denn sonst Variablen gut sein?

Worin besteht der Unterschied, ob ich aus einer Registervariable etwas hole und in eine Variable speichere vs. mein Script erzeugt Werte und die schreibe ich in Variablen?

Stehe da auf dem Schlauch …

Die weitere Frage wäre dann:

Wenn ich Werte zwischenspeichern will, die NICHT aus registerVariablen Stammen, z.B. die zulestz gedrückten 10 oder 20 Taster, wohin schreibe ich dann diese Werte? Muss ich dann eine Dumminstanz mit Registervariablen anlegen?

hmmm.

Es geht um die Menge der Daten und insbesondere um Binärdaten, wie sie durch die RegisterVariable weitergeleitet werden. Dafür sind die String Variablen nicht gedacht. Nutz den Puffer. Dafür haben wir ihn eingebaut. Oder nutzt die Variablen - aber sag mir nicht hinterher, dass deine Settings fehlerhaft sind.

Das ist wie mit dem PC wenn du den Stromstecker ziehst. Du kannst es machen… aber früher oder später wird dein PC mal nicht mehr booten :wink:

paresy

Die Binärzeichen haue ich ja vor dem Speichern raus.

DIE waren es auch, die ich als „problematisch“ aus dem Hinweis herausgelesen habe.

Ich akzeptiere ja gerne Hinweise. Aber die sollten dann vielleicht nicht nur en ainer speziellen Stelle stehen, sondern im allgemeinen Hinweis.

Also sollte z.B. bei „Vorgehensweisen“ oder noch besser, ein eigenes Kapitel, „LIMITATIONEN“ aufgeführt werden, was man warum nicht tun soll.

Kann ein User ja nicht erkennen, dass man im Jahr 2010 noch auf Limitationen achten muss, wie sie zu Cobol-Zeiten galten.

Wenn man es hingegen weiss …

Und mal ganz konkret:

Wie groß darf denn / sollte denn maximal eine String Variable werden?

Danke!
jwka

HILFE, noch ne Frage in diesem Zusammenhang:

Irgendwo MUSS ich doch Werte puffern (können), denn:

1.) bei jedem Aufruf von CSCKxxx, der eine Antwort zufolge hat, wird die Registervariable doch überschrieben

2.) ich zur weiteren Verarbeitung u.U. ein anderes als das gelieferte Format haben will (z.B. „bereinigte“ Strings (rawurldecode())

3.) Last but not Least:

Der Puffer wird nach dem Neustart von IP-Symcon gelöscht!

Ich würde mich über eine Erleuchtung sehr freuen, weil ich im Moment gerade gar nicht mehr sehe, dass ich IPS überhaupt zu was anderem als zum Visualisieren verwenden kann, denn ich will SEHR VIEL Daten Langzeit-aufzeichnen und das zur Laufzeit, also auch ein gutes Stück weit zeitkritisch (da fallen eigene Detai-Operationen eher weg) …

ich will SEHR VIEL Daten

Wer dafür keine Datenbank nimmt, sollte lieber in COBOL programmieren :smiley:

Sorry - aber ich verstehe deine Denkweisen nicht. Vielleicht kann ja jemand anders helfen, der dich und dein Konzept versteht. Ich kann es leider nicht.

  1. Nein. $IPS_VALUE kannst du in den Puffer konkatieren.

  2. Strings sind in IP-Symcon keine Rohdatenlangzeitspeicher. Immer noch nicht. Dafür gibt es Datenbanken. Dafür hat PHP beste Schnittstellen.

  3. Das ist so gewollt - Zwischenzeitlich wird dein Datenpuffer eh unsynchron geworden sein und die gepufferten Daten nutzlos.

  4. Denk dir einfach eine imaginäre Grenze von 1024 Zeichen pro String.

paresy

ok. danke für die Info.

1024 Byte ist ja schonmal was, wenngleich m.E. sehr wenig.

Mit „sehr viele Daten“ meine ich nicht etwa 15.000 Messwerte zu je 8 Byte in der Stunde - da würde ich selber auf die Idee kommen, eine Datenbank zu verwenden, und solcherlei würde ich dann IPS auch nicht zutrauen - zumindest nicht, ohne die eigentliche Aufgabe, die Haussteuerung, zu gefährden.

Aber vielleicht z.B. die ausgelösten Events (Tasterdrücke) in einem 48h Zeitraum oder einer Woche (z.B. als Modell für eine Anwesenheitssimulation) - das können dann zwar schon mal 300 Infos pro Tag sein mit vielleicht 10-20 Byte - würde ich schon gerne verarbeiten, OHNE gleich auf weitere Komponenten wie eine DB zurückgreufen zu müssen.

Ich halte es schon für „Kanonen auf Spatzen geschossen“, wenn man für Daten im Bereich von 50-100KB ne Datenbank bemüht. Sowas hat heute jedes simple Bild und eine kleine XLS Datei mit einer Handkasse für ein Quartal kommt auch auf diese Größe.

Vielleicht erinnerst Du Dich: Ich hatte ganz zu Anfang versucht, mit einigen Fragen die Grenzen des Systems auszuloten (da konnte ich derart gezielt gar nicht fragen, weil ich das System ja eben nicht kanne.

Und da wurde dann in den Antworten schon ein wenig geprahlt (http://www.ip-symcon.de/forum/f52/systemarchitektur-fragen-variablen-objektbaum-vs-array-per-include-8255/#post68233).

Und nun überfordere ich IPS schon, wenn ich mal ein paar Tausend Bytes in eine Variable ablegen will? Das passt m.E. nicht so richtig zusammen.

Hier noch ein paar Beispiele, warum ich gerne in Variablen etwas mehr abspeichern will:

  • Steuersquenzen für z.B. Squeezeboxen sollen vorgehalten und abgerufen werden können

  • Ambiences mit entsprechenden Werten für einzelne Aktoren sollen strukturiert abgelegt werden und dann von Scripten ausgelesen und an die Aktoren weitergegeben werden

  • Zustände wie z.B. der Aktuelle Zustand aller Aktoren soll gepuffert und später wiederhergestellt werden können

Das alles sind keine Massendaten, aber sie gehen halt schonmal über 1K raus. Und ich will diese Daten nicht „festverdrahtet“ in Arrays und Deteien ablegen, zumal sie ja teilweise zur Laufzeit des Systems erst entstehen bzw. die Werte dann erst bekannt sind.

Für sowas ist doch prinzipiell die Struktur in einem Objektbaum optimal. Wenn ich selber in einem externen File (oder einer DB) organisieren will, kann ich mich von IPS m.E. verabschieden, das wird Laufzeitprobleme ohne Ende geben, denn was IPS ja sicher im Speicher hält - jedenfalls teilweise - muss im falle eines Scripts jedesmal aufs neue ausgelesen werden.

Ich hoffe, ich habe ich mich jetzt verständlicher ausgedrückt.

Irgendwie kann ich mir einfach nicht vorstellen, dass meine Wünsche so fernab von den Möglichkeiten von IPS liegen bzw. dass man hier nur „hard coded“ Varianten fährt.

Den ersten Beitrag in diesem Thread sollte man übrigens löschen, um nicht andere mit meinen (gut gemeinten) Ansätzen in die Irre zu leiten, oder?

jwka