RS232 Werte nur bei Änderung an KNX übergeben

Moin.

Ich brauche einmal bitte eine Idee wie man es am Besten macht:

Ich ziehe mir den Status der Fenster über meine Alarmanlage durch einen aktiven RS232 Befehl gepolt alle 5sec. Die EMA sendet leider nichts von selbst.

Ich habe diese 45 Zeichen Lange HEX Kette mit lauter If Abfragen abgefragt (16Stck) welches dann ja auch alle 5sec gemacht wird.
Diese geben sich kontinuierlich dauern auf den KNX Bus.
Das ist ziemlich resoucn fressend.

Geht das auch anders? Denke um den Poll all 5sec komme ich nicht rum.

Lasse ich Kur zB in IPS alle Fenster Werte in eine Var schreiben, und erstelle dann 16 Ereignisse die auf Änderung reagieren und dann mit je ihrem eigenen Skript den Wert an KNX schicken - bei eben der Änderung?

Oder ….???

VG

Du möchtest den Zustand ja auch in Symcon haben. Also ist der korrekte Ansatz schon, die Werte auch in eine Symcon Variable zu schreiben. Jetzt könntest du grob folgendes machen:

if(GetValue($symconID) != $RS232_Wert){
    SetValue($symconID, $RS232_Wert);
    KNX_WriteDPT1($knxInstanzID, $RS232_Wert);
}

Da du schreibst, eine Kette von 16 IF Abfragen, würde ich das ggf. noch etwas anders strukturieren.
z.B. mit

$symconIDs = array(12345,32165,21546);
$i=0;
foreach($symconIDs as $ symconID){
    $RS232_Wert = substr($i*3,3, $rs232_zeichenkette); // ggf. noch eine weitere Methoode wie dechex, etc
    $i++;
    [hier den Part von oben]
}

Muss ich mal in Ruhe ausprobieren.

Dh ich generiere damit die IPS Variablen als Array.

Aber wie übergebe ich die an KNX nur bei Änderung? Ansonsten flute ich den KNX Bus.

Die Prüfung if(GetValue...) prüft, ob der Wert anders ist. Nur dann sendest du ihn auf den Bus und aktualisierst die Symcon Variable.

Das Array, etc. hilft dir nur dabei, dass nicht für 16 Sensoren einzeln zu machen, sondern alles in einem Abwasch zu erledigen. Dafür müsstest du vielleicht dein Ausgangsscript mal komplett senden, da ist das schnell integriert.

Moin.

das Problem ist ja das KNX immer den letzten Wert beibehält.
Dh ich muss immer if else prüfen und damit wird der KNX Bus geflutet.

Unten mal der gesamte Code.

Meine Gedanken, wo mir der entscheidende Funken noch fehlt wären:

a)
Wie kann ich nur an KNX übergeben, wenn eine Änderung vorliegt? Alle if abfragen in je ein Ereignis packen und auf Änderung des empfangenden RS232 HEX codes reagieren?
Macht das Sinn die ca. 16 if Abfragen in 16 „auslösende Ereignisse zu packen“?
Aber ich muss ja auch die KNX Werte von True wieder auf False setzen (Fenster auf / zu).- die setzten sich nicht von alleine wieder zurück…
b)
Macht es Sinn, den kompletten HEX code zu vergleichen oder macht es das besser, wenn man den in seine Einzelheiten (bytes) zerlegt? Und wie zerlege ich den überhaupt? Habe es als absoluter PHP Neuling noch nicht verstanden.
c)
Ich übergebe den ganzen HEX code als test ans KNX und werte den dort in einer Gira X1 Logik aus.
Hier kann ich aber max 14 Zeichen verarbeiten (Limitierung KNX) - also fällt das flach - es sei denn ich zerstückel den gesamten HEX Code und schicke den mir z.B. in 4 einzelne Pakete.

Ihr seht - Fragen über Fragen und mir fehlt die richtige Vorgehensweise…
Über ein Bsp Skript wäre ich dankbar…

<?php
// wenn das Skript von einer RegisterVariable-Instanz aus aufgerufen worden ist
RegVar_SetBuffer(32952, "");

if ($IPS_SENDER == "RegisterVariable")

{

		// bereits im Puffer der Instanz vorhandene Daten in $data kopieren HIER AUSKOMMENTIEREN
  		$data  = RegVar_GetBuffer($_IPS['INSTANCE']);
  
  		// neu empfangene Daten an $data anhängen
  		$data .= $_IPS['VALUE'];
  
  		
        // Inhalt von $data im Puffer der RegisterVariable-Instanz speichern
        RegVar_SetBuffer($_IPS['INSTANCE'], $data);


  // Daten in hex umwandeln
  $datastr = strToHex($data);
  IPS_LogMessage( "MC1200","".$datastr);
  
  
  // String in Variable ausgeben wenn mit 2 beginnt und gößer gleich 35 lang
  if(strpos($datastr, "2" ) == 0 and (strlen($datastr) >= 35)) {
     SetValue(21051 , $datastr);
      
      
      //übergibt zusätzlich noch gesamten string an KNX als text
      KNX_WriteDPT16(21274, GetValue(21051));
  }
 	
   }
  // abfragen
  if(GetValue(21051) == "21f1f280330191191000000000000000000191191001b3") {SetValue(30068, "extern bereit"); 
    KNX_WriteDPT1(58812, true);  
    } else { 
        KNX_WriteDPT1(58812, false);
    }

 if(GetValue(21051) == "21f1f2803309119100000000000000000119119100c3") {SetValue(30068, "intern bereit / Verschluss OG"); 
   KNX_WriteDPT1(58270, true);
   } else {
   KNX_WriteDPT1(58270, false);
   }

    if(GetValue(21051) == "21f1f28033012119100000000000000000219119100163") {SetValue(30068, "intern scharf"); 
      KNX_WriteDPT1(48587, true);
      } else {
          KNX_WriteDPT1(48587, false);}


// ########################### WEITERE 16 abfragen wie oben ##########################


function strToHex($string)
{
    $hex='';
    for ($i=0; $i < strlen($string); $i++)
    {
        IPS_sleep(25);
        $hex .= dechex(ord($string[$i]));
    }
    return $hex;
}
?>

Schau mal, ob du damit was anfangen kannst.

<?php
RegVar_SetBuffer(32952, "");
if ($IPS_SENDER == "RegisterVariable"){
	// bereits im Puffer der Instanz vorhandene Daten in $data kopieren HIER AUSKOMMENTIEREN
	$data  = RegVar_GetBuffer($_IPS['INSTANCE']);
	// neu empfangene Daten an $data anhängen
	$data .= $_IPS['VALUE'];
	// Inhalt von $data im Puffer der RegisterVariable-Instanz speichern
	RegVar_SetBuffer($_IPS['INSTANCE'], $data);

	// Daten in hex umwandeln
	$datastr = strToHex($data);
	IPS_LogMessage("MC1200", "".$datastr);
	  
	// String in Variable ausgeben wenn mit 2 beginnt und gößer gleich 35 lang
	if(strpos($datastr, "2" ) == 0 and (strlen($datastr) >= 35)) {
		SetValue(21051 , $datastr);
		//übergibt zusätzlich noch gesamten string an KNX als text
		KNX_WriteDPT16(21274, $datastr);
	}
} // Ende if RegisterVariable

$confarray = array( 
	array("21f1f280330191191000000000000000000191191001b3", 58812, "extern bereit"),
	array("21f1f2803309119100000000000000000119119100c3", 58270, "intern bereit / Verschluss OG"),
	array("21f1f28033012119100000000000000000219119100163", 48587, "intern scharf")
);

foreach($confarray as $conf){
	$newvalue = ($datastr == $conf[0]) ? true : false;
	$variableID = IPS_GetObjectIDByIdent("Value", $conf[1]);
	$oldvalue  = GetValueBoolean($variableID);
	if($newvalue && !$oldvalue){
		// neuer Wert true, alter Wert false, daher Änderung schreiben
		SetValue(30068, $conf[2]); 
		KNX_WriteDPT1($conf[1], true);  
	}elseif(!$newvalue && $oldvalue{
		// neuer Wert false, alter Wert true, daher Änderung schreiben
		KNX_WriteDPT1($conf[1], false);
	}
	// Else: aktuell nichts zu tun
}


function strToHex($string)
{
    $hex='';
    for ($i=0; $i < strlen($string); $i++)
    {
        IPS_sleep(25); // Wofür steht das?
        $hex .= dechex(ord($string[$i]));
    }
    return $hex;
}
?>

Ja super DANKE!

Noch ein problemchen:

$datastr (meine ich) bekommt noch zwischen den auswertenden Werten noch „Ack“ etc von der RS232.
Diese führen noch zu falsch ausgewerteten KNX write Befehlen - sprich zsichendruch kommmt bei eime richtigen „true“ immer mal ein „false“.

Daher frage ich oben ab, ob der HEX Code mit 2 beginnt und länger als 35 Zeichen ist.

Wie kann man das noch lösen?

Ok - habe ich hinbekommen durch - siehe unten - die if Abfrage nach 2 und >35 etwas weiter nach oben.

ABER: es kommt
„Notice: Undefined variable: datastr in C:\ProgramData\Symcon\scripts\28602.ips.php on line 30“ - warum?
d.h. hier:

$newvalue = ($datastr == $conf[0]) ? true : false;

Dennoch erhalte ich falsche false Meldungen:

Woher kommen diese abgehackten 14 Zeichen lange Meldungen?
Ich hatte irgendwann mal vorher damit gespielt, ist aber in diesem Skript oder auch woanders nicht mehr drin?
GGf Buffer löschen? Wie?

<?php
RegVar_SetBuffer(32952, "");
if ($IPS_SENDER == "RegisterVariable"){
	// bereits im Puffer der Instanz vorhandene Daten in $data kopieren HIER AUSKOMMENTIEREN
	$data  = RegVar_GetBuffer($_IPS['INSTANCE']);
	// neu empfangene Daten an $data anhängen
	$data .= $_IPS['VALUE'];
	// Inhalt von $data im Puffer der RegisterVariable-Instanz speichern
	RegVar_SetBuffer($_IPS['INSTANCE'], $data);

	// Daten in hex umwandeln
	$datastr = strToHex($data);
    if(strpos($datastr, "2" ) == 0 and (strlen($datastr) >= 35)) {
	IPS_LogMessage("MC1200", "".$datastr);
	  
	// String in Variable ausgeben wenn mit 2 beginnt und gößer gleich 35 lang
	
		SetValue(21051 , $datastr);
		//übergibt zusätzlich noch gesamten string an KNX als text
		KNX_WriteDPT16(21274, $datastr);
	}
} // Ende if RegisterVariable

$confarray = array( 
	array("21f1f280330191191000000000000000000191191001b3", 58812, "extern bereit"),
	array("21f1f2803309119100000000000000000119119100c3", 58270, "intern bereit / Verschluss OG"),
	array("21f1f28033012119100000000000000000219119100163", 48587, "intern scharf")
);

foreach($confarray as $conf){
	$newvalue = ($datastr == $conf[0]) ? true : false;
	$variableID = IPS_GetObjectIDByIdent("Value", $conf[1]);
	$oldvalue  = GetValueBoolean($variableID);
	if($newvalue && !$oldvalue){
		// neuer Wert true, alter Wert false, daher Änderung schreiben
		SetValue(30068, $conf[2]); 
		KNX_WriteDPT1($conf[1], true);  
	}elseif(!$newvalue && $oldvalue){
		// neuer Wert false, alter Wert true, daher Änderung schreiben
		KNX_WriteDPT1($conf[1], false);
	}
	// Else: aktuell nichts zu tun
}


function strToHex($string)
{
    $hex='';
    for ($i=0; $i < strlen($string); $i++)
    {
        IPS_sleep(25); // Wofür steht das?
        $hex .= dechex(ord($string[$i]));
    }
    return $hex;
}
?>

Wenn du die Foreach-Schleife in den Bereich der If-Abfrage if(strpos($datastr, "2" ) == 0 and (strlen($datastr) >= 35) verschiebst, sollte es gehen.

Serielle Schnittstellen schicken in mehreren Etappen. Du müsstest korrekterweise den Buffer auch sauber zusammensetzen und nur leeren, wenn er irgendwann überläuft. Aber das wäre dann der nächste Schritt.

Nee - leider nicht:

Denke ich habe 2 Probleme:

  1. Es wird einmal der Wert irgendwie abgekürzt - daher ist die true Bedingung nicht erfüllt für einen kurzen Moment - woher kommt das?

  2. die Variablen sind jetzt definiert - aber es wird der Wert true oder false nicht mehr auf die entsprechende KNX Variable geschrieben?

Ok - gelöst:

Es war die Tatsache, dass ich immer noch den gesamten >35 Zeichen langen Text an KNX übergeben habe im Code.
Aber KNX kann nur 14 Zeichen.
Die Zeile gelöscht und alles geht

DANKE!

Moin,

Nachdem oben es ja wunderbar funktioniert, hatte ich zum Anfang so einen mega Denkfehler :smiling_imp: - unglaublich!

Die HEX Ketten die ich abfrage sind nur für ein Fenster.
Wenn aber 2, 3 oder 5 oder 14 Fenster auf sind, sieht der Code immer anders aus.

Die Fett gedruckten Zahlen ändern sich von 0 auf 1 oder gar von 0 auf 10.

21f1f280330191191000000000000000000191191001b3l

Jemand noch eine Idee außer alle Möglichkeiten un-Smart aufzulisten?

Kannst du bitte mal eine Matrix hier reinstellen, bei der z.B. drei unterschiedliche Fenster alle 8 Kombinationen von offen und zu darstellen? Ich vermute relativ stark, dass die Fenster z.B: in den 10-20. Wert einkodiert sind, und dieser entweder 0 oder 1 haben kann. Es kam mir schon von Anfang an merkwürdig vor. Allerdings wollte ich nicht gleich all deine Arbeit in Frage stellen.

Sehr gerne.

    array("21f1f280330111910000000000010000011911910053", 26768, "OG: Sophia Seite"),
    array("21f1f280330111910000000000001000011911910053", 57710, "OG: Sarah Seite"),
    array("21f1f280330191191000000000000000000191191001b3", 58812, "extern bereit"),
	array("21f1f2803309119100000000000000000119119100c3", 58270, "intern bereit"),
	array("21f1f28033012119100000000000000000219119100163", 48587, "intern scharf"),
    array("21f1f280330111910000000000000001001911910043", 32662, "OG: Notruf"),
    array("21f1f280330111910000000000000000101911910043", 11163, "EG: Notruf"),
    array("21f1f280330411910000000000000000001911910063", 33544, "extern scharf"),
    array("21f1f280330111910010000000000000001911910043", 21234, "EG: Eingang"),
    array("21f1f280330111910001000000000000001911910043", 11540, "EG: Küche"),
    array("21f1f280330111910000100000000000001911910043", 41463, "EG: Essen"),
    array("21f1f280330111910000010000000000001911910043", 14293, "EG: Wohnen"),
    array("21f1f280330111910000001000000000001911910043", 31717, "EG: Gästebad"),
    array("21f1f280330111910000000100000000001911910043", 53013, "EG: Büro"),
    array("21f1f280330111910000000010000000001911910043", 31254, "OG: Elternbad"),
    array("21f1f280330111910000000001000000001911910043", 57272, "OG: Ankleide"),
    array("21f1f280330111910000000001000000011911910053", 50950, "OG: Schlafen"),
    array("21f1f280330111910000000000100000001911910043", 38621, "OG: Kinderbad"),
    array("21f1f280330111910000000000010000001911910043", 29071, "OG: Sophia"),
    array("21f1f280330111910000000000001000001911910043", 41380, "OG: Sarah"),
    array("21f1f280330111910000000000000010001911910043", 30617, "KG: Büro/Gäste/Vorrat"),
    array("21f1f280330111910000000000000100001911910043", 26610, "KG: Abstell/HWR")

So. In der Konfigurations-Array steht jetzt der Offset (sprich Position im String).

<?php
$confarray = array( 
	array(19, 58812, "extern bereit"),
	array(20, 58270, "intern bereit / Verschluss OG"),
	array(21, 48587, "intern scharf")
);

if($_IPS['SENDER'] == "Execute"){
	RegVar_SetBuffer($_IPS['INSTANCE'], ""); // Aufräumen, wenn über Konsole gestartet
}
if($_IPS['SENDER']== "RegisterVariable"){
	// bereits im Puffer der Instanz vorhandene Daten in $data kopieren HIER AUSKOMMENTIEREN
	$data  = RegVar_GetBuffer($_IPS['INSTANCE']);
	// neu empfangene Daten an $data anhängen
	$data .= $_IPS['VALUE'];
	// Inhalt von $data im Puffer der RegisterVariable-Instanz speichern
	RegVar_SetBuffer($_IPS['INSTANCE'], $data);

	// Daten in hex umwandeln
	$datastr = strToHex($data);
    if(substr($datastr, 0, 1) == "2" and (strlen($datastr) >= 35)) {
		IPS_LogMessage("MC1200", "".$datastr);
		RegVar_SetBuffer($_IPS['INSTANCE'], ""); // Registervariable aufräumen
		// String in Variable ausgeben wenn mit 2 beginnt und gößer gleich 35 lang
		//SetValue(21051 , $datastr); // eigentlich nicht nötig
		//übergibt zusätzlich noch gesamten string an KNX als text
		//KNX_WriteDPT16(21274, $datastr); // Verhindert KNX Fehler, weil Daten zu lang
	
		foreach($confarray as $conf){
			$substr = substr($datastring, $conf[0], 1);
			$newvalue = ($substr == "1") ? true : false;
			$variableID = IPS_GetObjectIDByIdent("Value", $conf[1]);
			$oldvalue  = GetValueBoolean($variableID);
			if($newvalue && !$oldvalue){
				// neuer Wert true, alter Wert false, daher Änderung schreiben
				SetValue(30068, $conf[2]); 
				KNX_WriteDPT1($conf[1], true);  
			}elseif(!$newvalue && $oldvalue){
				// neuer Wert false, alter Wert true, daher Änderung schreiben
				KNX_WriteDPT1($conf[1], false);
			}
			// Else: aktuell nichts zu tun
		}// Ende foreach
	} /// Ende if len>=35
} // Ende if RegisterVariable


function strToHex($string)
{
    $hex='';
    for ($i=0; $i < strlen($string); $i++)
    {
        IPS_sleep(25); // Wofür steht das?
        $hex .= dechex(ord($string[$i]));
    }
    return $hex;
}
?>

wow - Danke - es kommt aber leider noch ein Fehler:

14.02.2022, 15:30:11 | Register Variable |
Notice: Undefined variable: substr in C:\ProgramData\Symcon\scripts\28602.ips.php on line 30

Fatal error: Uncaught Error: Function name must be a string in C:\ProgramData\Symcon\scripts\28602.ips.php:30
Stack trace:
#0 {main}
thrown in C:\ProgramData\Symcon\scripts\28602.ips.php on line 30

line 30 ist:

$substr = $substr($datastring, $conf[0], 1);

Tja. Da war wohl ein Tippfehler. Direkt unter der foreach-Schleife bei $substr = substr($datastring, $conf[0], 1); hat sich nach dem = noch ein $ eingeschlichen.

Steht sogar gut in der Fehlermeldung: Functionsname muss ein string sein. Ist hier aber dummerweise eine Variable gewesen.

Tut mir leid - jetzt kommt:

Notice: Undefined index: INSTANCE in C:\ProgramData\Symcon\scripts\28602.ips.php on line 9

Warning: Instanz #0 existiert nicht in C:\ProgramData\Symcon\scripts\28602.ips.php on line 9

Eigentlich dürfte das nicht kommen, denn du sollst das Script ja nicht per Hand starten, sondern durch die Registervariable. Falls du es doch per Hand startest, wird eben genau dieser Teil mit Zeile 9 ausgeführt. Und weil dieser Part den Index INSTANCE nicht besitzt, kommt es zum Fehler. Du musst also die ID der RegisterVariable hier per Hand eintragen (oder mit IPS_GetParent, etc. herausfinden).

Die Register Variable updated sich ja alle 5 sec - sehe ich im Debug dass da auch was ankommt.

Aber irgendwie aktualisiert sich gerade nichts mehr.
Ich habe das hier wieder reingenommen und da kommt nichts mehr…

SetValue(21051 , $datastr); // eigentlich nicht nötig