Registervariable...Erklärung?

Hallo,

könnte mal jemand Noob-gerecht die Bedeutung der Registervariable erklären?

RegisterVariable - IP-Symcon :: Automatisierungssoftware

Was passiert genau mit dieser Registervariable, wenn man z.B. ein XBEE anbinden möchte? Und warum soll das alles über einen Buffer laufen?

Ich verstehe die Zusammenhänge nicht ganz :slight_smile:

Vielen Dank vorab!

RegisterVariable stellt eine Datenweiterleitungs- und -verarbeitungsschnittstelle zur Verfügung.

Als untergeordnete Instanz ist eine vorhandene Kommunikationsschnittstelle auszuwählen, z.B. eine serielle Schnittstelle. Werden von dieser neue Daten empfangen, wird das Ziel-Skript der RegisterVariable-Instanz ausgeführt. In diesem stehen die empfangenen Daten über $IPS_VALUE zur Verfügung.

Es gibt Datenquellen, bei denen erst mehrere empfangende Datensendungen eine sinnvolle Auswertung ermöglichen. Daher müssen die empfangenen Daten zwischengespeichert werden. Da Probleme auftreten können, wenn man binäre Daten in einer normalen String-Variable in IP-Symcon speichert (defekte IP-Symcon-Konfiguration), gibt es die Funktion RegVar_SetBuffer(integer $InstanzID, string $Puffer), der Daten im einen zur RegisterVariable-Instanz gehörigen Puffer speichert. Die im Puffer gespeicherten Daten lassen sich mit der Funktion RegVar_GetBuffer(integer $InstanzID) auslesen. Mit der Funktion RegVar_SendText(integer $InstanzID, string $Text) lassen sich Datenstrings über die Kommunikationsschnittstelle senden. Intern wird hierbei die passende Sendefunktion, wie z.B. COMPort_SendText, ausgeführt.

Folgendes Beispiel verkettet empfangene Daten und gibt durch ; separierte Datensätze bei Vervollständigung aus:

<?php
if ($IPS_SENDER == "RegisterVariable") // wenn das Skript von einer RegisterVariable-Instanz aus aufgerufen worden ist
{
    $data  = RegVar_GetBuffer($IPS_INSTANCE); // bereits im Puffer der RegisterVariable-Instanz vorhandene Daten in $data kopieren
    $data .= $IPS_VALUE; // neu empfangene Daten an $data anhängen

    if (strpos($data, ';')) // wenn das Trennzeichen ; in $data gefunden worden ist
    {
        $datasets = explode(';', $data); // $data in durch ; separierte Datensätze zerlegen
        for ($i = 0; $i < count($datasets) - 1; $i++) // alle nicht durch ; terminierten Datensätze ausgeben
        {
            echo "empfangener Datensatz: ".$datasets[$i]."
";
        }
        $data = $datasets[count($datasets) - 1]; // $data auf den Inhalt des letzten und damit unvollständigen Datensatzes setzen
    }

    RegVar_SetBuffer($IPS_INSTANCE, $data); // Inhalt von $data im Puffer der RegisterVariable-Instanz speichern
}
?>

Hallo Horst,

vielen lieben Dank für die ausführliche Erklärung, hat mir sehr geholfen!

Danke Horst,
das war auch für mich interessant.

Könnte man deinen Kommentar nicht noch in die Dokumentation der RegisterVariable bringen.
Ich gehöre leider zu den Menschen, die nach der Mittagspause neu angelernt werden müssen;) und sich deshalb gerne an die Dokumentation halten.
Auch der PHP-Code könnte unter Tipps hilfreich sein.

[Edit]
Jetzt hab ich auch noch gesehen, dass Du einen Link zu diesem Thread gelegt hast. Die Erklärung würde trotzdem gut direkt in die Doku passen.
[/Edit ]

Der Text war absichtlich so geschrieben, dass er in die Doku wandern könnte. Wollte nur noch abwarten, ob da jemandem noch was fehlt / unklar ist. Verlinkt hat den unterdessen jemand anderes.

Hallo,

ich muss doch noch mal nachhaken, der Respekt vor der Registervariablen ist mir einfach zu groß :slight_smile:

Aufgabenstellung:

  • Registervariable bekommt über ein XBEE Werte herein (z.B. „5“, „ok“)
  • das zugehörige Script soll diese Daten „auswerten“

Beispiel: Kommt eine 5 herein, soll eine 7 gesendet werden

Irgendwie habe ich die Zusammenhänge doch noch nicht so ganz verstanden, vor allem die „RegVar_SetBuffer“…brauche ich die überhaupt oder kann ich direkt mit „RegVar_SendText“ wieder schreiben? Und wird das Script automatisch bei einer Änderung der Registervariablen aufgerufen?

So sieht mein Script aus:

if ($IPS_SENDER == "RegisterVariable") // wenn das Skript von einer RegisterVariable-Instanz aus aufgerufen worden ist
		{
    	$data  = RegVar_GetBuffer($IPS_INSTANCE); // bereits im Puffer der RegisterVariable-Instanz vorhandene Daten in $data kopieren
        if ($data = 5)
    		{
		  RegVar_SetBuffer($IPS_INSTANCE, "");
		  RegVar_SendText($IPS_INSTANCE, 7);
    		}
		}
else
{
}


Hilfe :-))

Verkürzte Version.

$data  = $IPS_VALUE;
if ($data == 5)
{
    RegVar_SendText(IDRegVar, 7);
}

Kommt immer drauf an, für was man es nutzt.

Hallo Rainer,

vielen Dank für die schnelle Hilfe!

Wann würde denn diese Version von Dir an Ihre Grenzen stoßen? Sorry für die blöde Frage…ich raff die Unterscheide irgendiwe noch nicht ganz :frowning:

Das kommt wierderum darauf an, wie die Daten von der Schnittstelle kommen. Wenn Du einen Datensatz mit 4000byte auswerten willst, macht es Sinn zwischen zuspeichern.
Wie gesagt, kommt immer auf den Fall an.

Ich an deiner Stelle, würde mehr debuggen, dann versteht man auch den Zusammenhang.

Danke erstmal!

Muss ich Dein Script noch bei der Registervariable als Zielscript eintragen oder reicht das, wenn es logisch unter der Registervariable „hängt“?

Mit dem Debuggen hast Du Recht…aber gerade an der Registervariable habe ich Angst, da in der Doku von zerschossenen Installationen die Rede ist wenn man da etwas falsch macht.

als Zielscript eintragen, sonst geht nix.

Danke!!! :loveips:

Zum Zerschießen: Das bezieht sich darauf, dass Du nicht Datensätze, die Du von der RegisterVariable-Instanz empfangen hast, in eine IPS-String-Variable speichern (SetValue) sollst. Da sind dann unter Umständen Binärzeichen drin, mit denen der XML-Parser für die settings.xml nicht zurecht kommt. Willst Du also zwischen mehreren empfangenen Datensätzen zwischenspeichern, solltest Du dafür RegVar_SetBuffer/RegVar_GetBuffer verwenden. Bekommst Du direkt immer fertig verarbeitbare Daten, sind diese beiden Befehle nicht nötig für dein Skript.

Vielen Dank Horst für die Erklärung!

Jetzt bin ich beruhigt, bei mir kommen nur „fertige“ Daten in Form einer Zahl oder einer kurzen Zeichenkette über die Registervariable herein - das sollte damit ok sein.

Danke nochmal an alle für die Hilfe!

…und hoffte, dass das mit der IPS 2.1, die ich eigentlich nach Anleitung erfolgreich migriert hatte, so weiter geht. Aber die Knadenfrist für das direkte Schreiben in eine Stringvariable durch Registervariable scheint mit der V2.1 abgelaufen zusein, denn danach liefen entsprechende Scripts nicht mehr.
Keine Frage… ich habe mit RegVar_Get u. Set… IPS_SENDER, VALUE u. INSTANCE herumprobiert und jetzt zum 3. mal meine alte V2.0 zurück gespielt.

Wenn mir jetzt nochmal jemand die Zusammenhänge anhand meines eigenen Scripts erklären könnte, dann würde ich es vielleicht besser verstehen und alle weiteren selbst umsetzen können.

Ich möchte einfach die nächsten 3 Wochen (bis der Stress im neuen Jahr wieder los geht) dazu nutzen, die V2.1 respektive Beta 2.2 zu migrieren, um auf dem Laufenden zu bleiben.

Hier mein „Lieblingsscript“ zum Auswerten eines Leveljet über die ser. Schnittstelle:

<?
/*
*************************************************
 Heizöl-Füllstand überwachen (LEVELJET)
*************************************************
File     : LEVELJET_LOG.ips.php
Trigger  : Variable LEVELJET
Interval : 1 Sekunde
*/


if (GetValueString(32686 /*[0. Keller\Heizung\LevelJet (Keller)]*/ ) == "")
   return;
if (!IPS_SemaphoreEnter("RegisterVariable_Log_run",1))
   return;
IPS_Sleep(800);
$buffer = GetValueString(32686 /*[0. Keller\Heizung\LevelJet (Keller)]*/ );
SetValueString(32686 /*[0. Keller\Heizung\LevelJet (Keller)]*/ ,"");
list($usec, $sec) = explode(" ", microtime());
$start_time = strftime("%H:%M:%S",$sec);

// Debugmodus = true schreibt Log - false beendet Logging
$ldebug = false;

// Datenblock zerlegen und Menge errechnen
$length = strlen($buffer);
if ($ldebug)
    echo "Länge: ". $length ."
";
if ($length == 11)
{
    $high_byte = ord($buffer{7});
    $low_byte = ord($buffer{6});
    $menge = $high_byte * 256 *10 + $low_byte * 10;
    SetValueInteger(55389 /*[0. Keller\Heizung\Heizöltank Füllstand (Keller)]*/ ,$menge);
}


if ($ldebug){
// Logfile öffnen (Pfad und Datei)
    $handle = fopen("H:/LevelJet/testlog.txt","a");
    
// Message verarbeiten
    $length = strlen($buffer);
    if ($length !== 0)
    {
        fwrite($handle,$start_time." > ");
        for ($i=0; $i<$length; $i++)
        {
            $dbyte = ord($buffer{$i});
            fwrite($handle, set_byte($dbyte)." ");
        }
        fwrite($handle,"
");
    }
    fclose($handle);
}

function set_byte($byte){
   if ($byte < 16)
      return "0".dechex($byte);
   else
      return dechex($byte);
}
IPS_SemaphoreLeave("RegisterVariable_Log_run");
?>

Die Registervariable hätte die ID 48762 und schreibt bisher in die Stringvariable mit der ID 32686 (siehe Script) und das Script wurde durch diese Variable bei Update getriggert.

Wie muss ich nun die Verbindung zur Registervariable umsetzen, dass es wieder läuft.

Bitte um Hilfe für einen, der gerne sagt… „never changing a running sytem“ (oder in dem Fall auch Dummie genannt)… aber nun dazu gezwungen ist, um die Vorteile der neuen Versionen zu erleben.

Diese Registervariable-Geschichte war bisher das Einzigste, was mich von einem Update abhielt :rolleyes:
Ich hoffe, dass meine Frage, da der thread ja im Wiki gelinkt ist, die „Angelegenheit“ nicht zu sehr aufbläht. Aber u.U. hilft es dem Einen oder Anderen den Sachverhalt noch besser zu verstehen…

Bei mir läufts folgendermaßen:

  • Registervariable
  • Zielscript, dieses muss der Registervariablen unter „Eigene Aktion“ zugewiesen sein.

Das Script sieht dann z.B. bei mir so aus:

<?

$data  = $IPS_VALUE;
if ($data == "Online")
{
RegVar_SendText(13467 /*[XBee Wetterstation\Register Variable]*/ , chr(27)."YH".chr(1));
IPS_Sleep(10);
.
.
.
}

Sobald sich an der Registervariable was ändert, wird automatisch das Script „getriggert“ - dort kannst Du dann Deine Befehle verarbeiten (bei mir meldet sich mit „Online“ die Wetterstation bei Stromzufuhr an). Habe bei mir allerdings auf die Verwendung eines Buffers verzichtet, ich weiß nicht ob das bei Dir auch vernünftig ist. Bei richtig großen Datensätzen ist das mit einem Buffer vermutlich besser und es besteht nicht die Gefahr, dass man IPS mit irgendwelchen Steuerzeichen „abschießt“.

Hallo nancilla,

wie dreamy schon beschrieben hat, das Script in der Registervariablen eintragen.
In dem Script muß nur eine Zeile geändert werden.

$buffer = IPS_VALUE; 

fertig.

Gruß
Attain

Vielen Dank erstmal eurer Antworten.

Selbstverständlich habe ich das Script in die Registervariable eingetragen (bisschen gelesen habe ich vorher schon…), aber wenn ich das so ändere:

<?
/*
*************************************************
 Heizöl-Füllstand überwachen (LEVELJET)
*************************************************
File     : LEVELJET_LOG.ips.php
Trigger  : Variable LEVELJET
Interval : 1 Sekunde
*/


//if (GetValueString(32686 /*[0. Keller\Heizung\LevelJet (Keller)]*/ ) == "")
//   return;
//if (!IPS_SemaphoreEnter("RegisterVariable_Log_run",1))
//   return;
//IPS_Sleep(800);
$buffer = IPS_VALUE;
//SetValueString(32686 /*[0. Keller\Heizung\LevelJet (Keller)]*/ ,"");
list($usec, $sec) = explode(" ", microtime());
$start_time = strftime("%H:%M:%S",$sec);

// Debugmodus = true schreibt Log - false beendet Logging
$ldebug = false;

// Datenblock zerlegen und Menge errechnen
$length = strlen($buffer);
if ($ldebug)
    echo "Länge: ". $length ."
";
if ($length == 11)
{
    $high_byte = ord($buffer{7});
    $low_byte = ord($buffer{6});
    $menge = $high_byte * 256 *10 + $low_byte * 10;
    SetValueInteger(55389 /*[0. Keller\Heizung\Heizöltank Füllstand (Keller)]*/ ,$menge);
}


if ($ldebug){
// Logfile öffnen (Pfad und Datei)
    $handle = fopen("H:/LevelJet/testlog.txt","a");
    
// Message verarbeiten
    $length = strlen($buffer);
    if ($length !== 0)
    {
        fwrite($handle,$start_time." > ");
        for ($i=0; $i<$length; $i++)
        {
            $dbyte = ord($buffer{$i});
            fwrite($handle, set_byte($dbyte)." ");
        }
        fwrite($handle,"
");
    }
    fclose($handle);
}

function set_byte($byte){
   if ($byte < 16)
      return "0".dechex($byte);
   else
      return dechex($byte);
}
//IPS_SemaphoreLeave("RegisterVariable_Log_run");
?>

… ändert sich am Ergebnis auch nichts.

SetValueInteger(55389 /*[0. Keller\Heizung\Heizöltank Füllstand (Keller)]*/ ,$menge);

wird nicht aktualisiert.
Das Script wird getriggert, aber die (Ergebnis)IntegerVariable wird nicht mehr aktualisiert.

Hallo,

Die Daten werden von der Comschnittstelle nur „Packetweise“ empfangen. Deswegen wird die Länge des Datensatzes nicht 11 Bytes lang sein.

if ($length == 11) 

Deswegen wird die Integervariable nicht geschrieben.
Du solltes zwischen Com Instanz und Registervariablen noch einen Cutter einbauen.

Gruß

…oder Du schreibst mit SetBuffer die Daten wieder zurück und prüfst bis die Daten 11Byte lang sind und holst sie mit GetBuffer wieder.