RS485 Befehl senden und Rückgabe auslesen

Hallo Zusammen,

ich habe mittlerweile einen US-Sensor bekommen um einen Tank auszulesen.

Jetzt habe ich eine Registervariable angelegt, den RS485 Com-Port als Instanz und ein Skript, welches den Auslesebefehl sendet. Dazu ist bei der RegVar das Skript als Ziel, die übergeordnete Instanz ist der Com-Port.

In der RegVar laufen nun irgendwie Daten auf, ich bekomme aber nicht mal mit „echo $data“ was zurück - ich habe das in allen Kombinationen probiert, aber die Rückgabe bleibt aus.
Dazu laufen bei einmaligem Ausführen in der RegVar mehrfach Daten auf, als ob das Skript mehrfach laufen würde.

Im Endeffekt will ich nur die Rückgabe weiterverarbeiten (von Hex zu ASCII und dann aus dem Text was aus & abschneiden. (In ASCII sollte „RL010012004C“ kommen, davon benötige ich die „1200“ (mm)).

Hier das Skript:

<?
$com =14246;
$reg=13446 /*[Messsystem\Heizöl\REG_VAR RS485]*/;
$code = "\x24\x52\x4C\x30\x31\x32\x33\x0D\x0A";

	COMPort_SetOpen($com, true);
	IPS_ApplyChanges($com);  

RegVar_SetBuffer($reg, "");

COMPort_SendText ($com, $code.chr(13)); 
 
	COMPort_SetOpen($com, false);
	sleep (1);
	IPS_ApplyChanges($com);  

if ($IPS_SENDER == "RegisterVariable")
{
  // bereits im Puffer der Instanz vorhandene Daten in $data kopieren
  $data  = RegVar_GetBuffer($reg);
  // neu empfangene Daten an $data anhängen
  $data = $IPS_VALUE;
  // Inhalt von $data im Puffer der RegisterVariable-Instanz speichern
  RegVar_SetBuffer($reg, $data);
  //debug_log(IPS_GetName($reg), "data: $IPS_VALUE
");
echo $data;
 }
?>

Wenn ich alles nach dem „If“ weg lasse und nur „echo $data“ einfüge, dann werden in der RegVar z.B. für 13 Sekunden weiter Daten empfangen - Buffer bleibt aber leer (gerade getestet, aber immer unterschiedlich lange).

Zudem bewirkt „sleep (1)“ bei mir nicht 1ms pause sondern 1s, bei 100 versucht er 100s pause zu machen! (Steht in der Doku anders…)

Hat wer jemand eine Idee - ich habe bisher nie selbst mit RegVars gearbeitet - bzw. nichts selbst geschrieben.
Danke & Gruß,
Maeffjus

Wenn Dein Gerät erst sendet, wenn es ein Befehl bekommt, dann würde ich erst einmal schauen was nach dem Befehl an Daten ankommt.

Danach ev einen Cutter verwenden, je nach Daten.

Dieser Cutter wäre die übergeordnete Instanz einer Registervariable und dessen eingetragenes Ziel-Script hat die Aufgabe die Daten der/den Variablen zu übergeben.

Aber ich kenne Dein Gerät nicht
Gruß Helmut

Hey Helmut,

das kommt an:

26 8D 1A 66 CC 30 30 30 33 39 30 35 35 0D 

Ich glaube der Sensor spuckt fast nie mehr aus - selten mehrere Zeilen, aber nicht im normalen Betrieb.
Mein Problem ist, ich sehe es in der RegVar, habe aber keine Ahnung wie ich das in eine normale Variable schreiben kann.

Haste mal ein Link zu der Beschreibung des Sensors?

Und kannst Du mal den Hexwert UND die ASCII Werte der Antwort darstellen

Sind mehrere Befehle mit anderen Antworten möglich, das könnte in einem Link zu finden sein.
Gruß Helmut

Hmm ja, das ist was durcheinander - Chinakram halt :smiley:
Mich interessiert eig. nur die Liquid-Height bzw. je nachdem sogar besser die Air height…
Hier die Befehle & Antworten (das mit der Prüfsumme bekomme ich auch nicht hin):
Dropbox - Communication_Protocol_DF550_DF520_Ultrasonic_Sensro_V1.7.pdf
Die Befehle für RS485 sind wie bei RS232 gleich.

Hier das „Datenblatt“ (Ich habe den 2m-Sensor):
Dropbox - DF550_Ultrasonic_Level_Sensor_Manual_V3.2.pdf

Aber ich finde das Datenblatt hilft nicht wirklich viel.
Gruß,
Matthias

Please contact with Dingtek about the protocol issue.

Aus den PDF’s kann ich nichts rauslesen, Du könntest mehrere Füllstände simulieren und sehen welche Daten sich verändern.
Gruß Helmut

Ich glaube wir reden aneinander vorbei:

Im Endeffekt will ich nur die Rückgabe weiterverarbeiten (von Hex zu ASCII und dann aus dem Text was aus & abschneiden. (In ASCII sollte „RL010012004C“ kommen, davon benötige ich die „1200“ (mm)).

Das kommt zurück - da sist ja auch alles kein Problem, mein Problem ist - wie auch beschrieben, dass der Sensor das als HEX schickt, es in der RegVar ankommt, ich aber keine Ahnung habe wie ich es in einen String o.Ä. bekomme.
Daraus ASCII machen usw. ist jetzt nicht gefragt, Fragestellung ist:

Wie bekomme ich den HEX-Wert aus der RegVar in eine Variable.

Nee, wir reden nicht anander vorbei, Du hast eine Hexzeile gepostet, darauf hin habe ich erklärt wie ich es machen würde.

Wenn Du die Stelle kennst und die Zeichen davor und dahinter immer gleich sind, dann kennst Du schon welche Zeichen in den Cutter rechts und links geschrieben werden können.

Damit ist es fast fertig, nur noch die Registervariable verarbeiten, fertig.
Gruß Helmut

Ja, aber an dem verarbeiten hängt es ja gerade. Ich bekomme die Daten nicht da „raus“.
Mit Parser, explode oder so bekomme ich das hin!
Ich würde zuerst aus HEX einen ASCII string machen, dann sind die Zeichen so wie in meinem Beispiel, davon schneide ich alles ab bis auf die vier Stellen die ich brauche und fertig.
Gruß,
Matthias

Im Moment kann ich nicht helfen, ev. heute Abend, hier schon mal ein Link zur Software und ein PDF
Gruß Helmut

Com_Protocol_DF550_DF520_Ultrasonic_Sensro_V1.7.pdf (347 KB)

Vielleicht einfach mal die aktuelle IPS Systemvariablen nutzen.
$_IPS[‚VALUE‘]
Michael

Vielen Dank dafür - ich hatte das Tool zwar, aber diese Version ist neuer!
Jetzt können auch Lesekommandos geschickt werden.
Aber das hilft mir mit der RegVar nicht wirklich.
Wenn ich das Skript aus Post#1 ausführe, dann sieht das Debugging dafür so aus:

(Skript)

<?
$com =14246 /*[Serial Port_RS485]*/;
$reg=13446 /*[Messsystem\Heizöl\REG_VAR RS485]*/;
$code = "\x24\x52\x4C\x30\x31\x32\x33\x0D\x0A";

	COMPort_SetOpen($com, true);
	IPS_ApplyChanges($com);  
RegVar_SetBuffer($reg, "");

COMPort_SendText ($com, $code.chr(13)); 
 
	COMPort_SetOpen($com, false);
	sleep (1);
	IPS_ApplyChanges($com);  

echo $data;

?>

(Debug der RegVar)

Und die Frage ist, wie kommen die Werte (also ich brauche nur einen davon und zwar nur einmal pro Skriptaufruf) in eine Variable?

Gruß,
Matthias

Irgendwie passt dein ganzen Script nicht so richtig.
Wenn es über die RegVar getriggert wird, macht es keinen Sinn den Port im Script zu öffnen, Daten zu senden und dann den Port zu schließen.
Da fehlt eine Abfrage des $_IPS[‚SENDER‘] auf TimerEvent oder Execute.
Dann würde ich den Port nicht öffnen schließen, sondern den in der Konsole einmalig öffnen und dann offen lassen.
In deinem letzten Script fehlt dann die Abfrage der Daten komplett. $data wird ja nie befüllt.
Die Daten liegen in $_IPS[‚VALUE‘].
Zusätzlich solltest du einen Cutter zwischen SerialPort und RegVar einbauen, mit rechtes Trennzeichen HEX 0D.
Dann noch mal testen.
Michael

Hier meine Anleitung, wie ich es gemacht hätte, wie schon in meinem ersten Beitrag geschrieben:

Comport erstellen und offen lassen

Ein zyklisches Script zur Requestanforderung „Füllstand“ und ein Script zur Variablen Zuweisung erstellen

Cutter erstellen, rechtes und linkes Trennzeichen einstellen, übergeordnete Instanz Serial Port

Registervariable erstellen, übergeordnete Instanz Cutter, Zielscript ist Script der Zuweisung

Deine Cutter Begrenzung rechts Links kann andere Daten haben, mußt Du testen, und Dein Ergebnis ist im Beispiel ein String, ev mußt Du Das anpassen

AufrufScript:

 <? 
$com =14246; 
$reg=13446; 
$code = "\x24\x52\x4C\x30\x31\x32\x33\x0D\x0A"; // Aufruf Code, mit Füllstand antworten


COMPort_SendText ($com, $code); 

// Dieses Script wird alle 10 Min aufgerufen, also Ereigniss erstellen

   // COMPort_SetOpen($com, true); // warum den Port nicht offen lassen, da kommen auch die Antworten rein
   // IPS_ApplyChanges($com);      // nur nicht wenn er zu ist.
//RegVar_SetBuffer($reg, ""); 

//COMPort_SendText ($com, $code.chr(13));  // warum nochmal chr(13) ?
  
   // COMPort_SetOpen($com, false); 
  // sleep (1); 
   // IPS_ApplyChanges($com);   

//echo $data; 

?>  

Ergebnisscript:

 <?

  $Fuellstand=  $_IPS['VALUE']

 SetValueString(1234, $Fuellstand); // Wenn Deine Anzeige eine Stringvariable ist steht dort dann der Füllstand
                                     // wenn es eine andere Art Variable mußt Du den String wandeln

?>   

Teste mal ob es Dich weiter bringt
Gruß Helmut

So, ich hatte zwischezeitlich mit dem Cutter probiert - ging aber nicht.
Die letzten beiden Stellen sind eine Prüfsumme die variiert, daher nun mit „Substr“. Im Endeffekt war mir die Funktionsweise einer RegVar nicht klar, jetzt läufts :wink:

Messung durchführen:

<?
$com =14246 /*[Serial Port_RS485]*/;
$reg=13446 /*[Messsystem\Heizöl\REG_VAR RS485]*/;
$code = "\x24\x52\x4C\x30\x31\x32\x33\x0D\x0A";

	COMPort_SetOpen($com, true);
	IPS_ApplyChanges($com);  

	COMPort_SendText ($com, $code.chr(13)); 
 
 	sleep (1);
	COMPort_SetOpen($com, false);
	IPS_ApplyChanges($com);  

?>

Daten auswerten:

<?
if ($_IPS['SENDER'] == "RegisterVariable") {
    $data = $_IPS['VALUE'];
	
	$data=substr($data, 7, 4); //relevanten Teil aus String ausschneiden
	
	settype($data,"Integer"); 
	SetValueInteger(58140 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllhöhe Heizöl Tank 1]*/, $data);
	settype($data,"Float");
	$liter=(2000/1500)*$data;
	SetValueFloat(50304 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllmenge Heizöl Tank 1]*/, $liter);
		}
?>

Dazu noch der Einbau (mit provisorischer Verkabelung und staubiger Wand…):
Die Platine ist ein „USR-TCP232-T24V“ Serial to Ethernet-Modul für ~22€.
(Läuft mit virtuellem COM-Port auf dem Server)

Jetzt fehlen noch zwei weitere Sensoren und eine saubere Verkabelung.
Wenn jemand eine Idee hat, wie man elegant drei Sensoren an einem bus abrufen kann… (die Sensoren haben unterschiedliche ID’s - diese sind innerhalb der ersten Zeichen der Antwort am Comport).
Ich meine, drei Skripe gingen - sind aber uncool, ich glaube man müsste das erste Skript evtl. 3x hintereinander laufen lassen und den „code“ jeweils anpassen. (das wäre für mich kein Problem, es ändert sich nur die Prüfsumme und ID)

$code = "\x24\x52\x4C\x30\x31\x32\x33\x0D\x0A";

Wo es mir vor graust ist die Auswertung, hier kommen ja alle Signale an einem Punkt an und müssen dann zugeordnet werden - ggf. könnte man mit Substr alles bis auf die ID wegschneiden, diese auswerten und dann den String jeweils zuordnen.

@Helmut: Ich schalte den Comport übrigens aus folgendem Grund ab: Es gibt keinen Grund ihn anzulassen, der Sensor sendet nur wenn er angesprochen wird und dazu rufe ich alle 10min ab - wieso 9:59 den Port offen lassen?
So kann ich - jedenfalls im Moment beim einrichten - jederzeit mit dem Config-Tool drauf zugreifen.
Übrigens: Wieso ist „chr(13)“ doppelt?
Letzter Punkt: Hat jemand eine Ahnung wie man kürzer als 1s das Skript anhält, Sleep sollte ja laut PHP Doku in ms angegeben werden, ist aber faktisch in Sekunden!

warum chr(13) nochmal stellt sich, weil ich sah, dass im Absatz 4.3 der Befehl mit Hex 0D und 0A abgeschlossen wird.
Und Du hast nochmal mit 13= Hex0D abgeschlossen.

Und zur Verkabelung, hattest Du nicht RS485? Kannst doch alle an den RS485 Bus nehmen?
Gruß Helmut

Edit Du hast 3 Heizöltanks, gleichen Die sich nicht aus?

Wenn es denn sein soll, 3 Sensoren, dann könntest Du die Auswertung so machen:

<?
if (($_IPS['SENDER'] == "RegisterVariable") or ($_IPS['SENDER'] == "Execute"))
{
  $dataorginal = $_IPS['VALUE'];     // zum Probieren ev. remen
  //$dataorginal="*RL020012004C";      // zum Probieren ev. remen
   	$WelcherTank=substr($dataorginal, 3, 2); //Sensor ID aus String ausschneiden
    $dataTank=substr($dataorginal, 7, 4); //Daten des Sensors aus String ausschneiden
	
    //echo $WelcherTank."    ".$dataTank;
 If ($WelcherTank=="01") 
 {
 	echo "Tank 01 hat ".$dataTank;
	settype($data,"Integer"); 
    SetValueInteger(58140 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllhöhe Heizöl Tank 1]*/, $dataTank);
    settype($data,"Float");
    $liter=(2000/1500)*$data;
    SetValueFloat(50304 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllmenge Heizöl Tank 1]*/, $liter);
 }
 If ($WelcherTank=="02") 
 {
	echo "Tank 02 hat ".$dataTank;
	settype($data,"Integer"); 
    SetValueInteger(12345 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllhöhe Heizöl Tank 2]*/, $dataTank);
    settype($data,"Float");
    $liter=(2000/1500)*$data;
    SetValueFloat(12345 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllmenge Heizöl Tank 2]*/, $liter);	
 } 
 If ($WelcherTank=="03")   
 {
	echo "Tank 03 hat ".$dataTank;
	settype($data,"Integer"); 
    SetValueInteger(12345 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllhöhe Heizöl Tank 3]*/, $dataTank);
    settype($data,"Float");
    $liter=(2000/1500)*$data;
    SetValueFloat(12345 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllmenge Heizöl Tank 3]*/, $liter);		
 }
}
?> 

Hey Folks…

I’m done:

  1. Sensoren Triggern (ID 01-03):
<?
$com =14246 /*[Serial Port_RS485]*/;
$reg=13446 /*[Messsystem\Heizöl\Ultraschall Tank rs485\REG_VAR RS485]*/;
//$code = "\x24\x52\x4C\x30\x31\x32\x33\x0D\x0A";
//Tank02 //24 52 4C 30 32 32 34 0D 0A
//Tank03 //24 52 4C 30 33 32 35 0D 0A

for ($i = 1; $i <= 3; $i++) {
    If ($i ==1) {
	$code = "\x24\x52\x4C\x30\x31\x32\x33\x0D\x0A";
	COMPort_SetOpen($com, true);
	IPS_ApplyChanges($com);  

	COMPort_SendText ($com, $code.chr(13)); 
 
 	IPS_Sleep(1500);
	COMPort_SetOpen($com, false);
	IPS_ApplyChanges($com);
	IPS_Sleep(1500);}  
	
	If ($i ==2) {
	$code = "\x24\x52\x4C\x30\x32\x32\x34\x0D\x0A";
	COMPort_SetOpen($com, true);
	IPS_ApplyChanges($com);  

	COMPort_SendText ($com, $code.chr(13)); 
 
 	IPS_Sleep(1500);
	COMPort_SetOpen($com, false);
	IPS_ApplyChanges($com);
	IPS_Sleep(1500);}  
	
	If ($i ==3) {
	$code = "\x24\x52\x4C\x30\x33\x32\x35\x0D\x0A";
	COMPort_SetOpen($com, true);
	IPS_ApplyChanges($com);  

	COMPort_SendText ($com, $code.chr(13)); 
 
 	IPS_Sleep(1500);;
	COMPort_SetOpen($com, false);
	IPS_ApplyChanges($com);
	IPS_Sleep(1500);}  
	}

?>
  1. Daten Empfangen und zuordnen. (Übrigens steht leider keine „richtige“ ID in der Sensorantwort, bzw. IPS dekodiert das zu ziemlichem Murks, daher rechne ich die Antwort in Hex um und weiß, dass bei den Sensoren c, 6, 9 an einer Stelle steht.
<?
if ($_IPS['SENDER'] == "RegisterVariable") {
    $data = $_IPS['VALUE'];
	
	 
	$hex = bin2hex($data);
	$tanknr=substr($hex, 9, 1); //Sensor ID aus String ausschneiden (Tank 1 in hex = "C", Tank 2 in hex 0 = "9", Tank 3 in hex = "6")
	settype($tanknr,"String"); 
	
	
	If ($tanknr=="c"){ 			//TANK 1
	$data=substr($data, 7, 4); //relevanten Teil aus String ausschneiden
	
	settype($data,"Integer"); 
	SetValueInteger(58140 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllhöhe Heizöl Tank 1]*/, $data);
	settype($data,"Float");
	$liter=(2000/1500)*$data;
	SetValueFloat(50304 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllmenge Heizöl Tank 1]*/, $liter);
	$tank_inv_1=100-(($data/1500)*100);
	round($tank_inv_1,0);
	settype($tank_inv_1,"Integer"); 	
	SetValueInteger(37583 /*[Messsystem\Heizöl\Heizölfüllstand Shutter-Display\Füllmenge Heizöl inv Tank 1]*/, $tank_inv_1);}
	
	
	If ($tanknr=="9"){ 			//TANK 2
	$data=substr($data, 7, 4); //relevanten Teil aus String ausschneiden
	
	settype($data,"Integer"); 
	SetValueInteger(27591 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllhöhe Heizöl Tank 2]*/, $data);
	settype($data,"Float");
	$liter2=(2000/1500)*$data;
	SetValueFloat(10374 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllmenge Heizöl Tank 2]*/, $liter2);
	$tank_inv_1=100-(($data/1500)*100);
	round($tank_inv_1,0);
	settype($tank_inv_1,"Integer"); 	
	SetValueInteger(41889 /*[Messsystem\Heizöl\Heizölfüllstand Shutter-Display\Füllmenge Heizöl inv Tank 2]*/, 
$tank_inv_1);}
	
	
	If ($tanknr=="6"){ 			//TANK 3
	$data=substr($data, 7, 4); //relevanten Teil aus String ausschneiden
	
	settype($data,"Integer"); 
	SetValueInteger(47622 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllhöhe Heizöl Tank 3]*/, $data);
	settype($data,"Float");
	$liter3=(2000/1500)*$data;
	SetValueFloat(38232 /*[Messsystem\Heizöl\Ultraschall Tank rs485\Füllmenge Heizöl Tank 3]*/, $liter3);
	$tank_inv_1=100-(($data/1500)*100);
	round($tank_inv_1,0);
	settype($tank_inv_1,"Integer"); 	
	SetValueInteger(52415 /*[Messsystem\Heizöl\Heizölfüllstand Shutter-Display\Füllmenge Heizöl inv Tank 3]*/, 
$tank_inv_1);}
	}
?>

Dazu wird noch eine Variable geschrieben, welche den Tankwert invertiert in Prozent angibt: (100%-Füllstand in %)
Damit steuere ich ein Skript, das den Tank visualisiert.
Allerdings bekomme ich es nur hin, dass das „falschherum“ anzeigt - also anstatt einen Kasten zu vergrößern mit dem Füllstand vergrößere ich den Teil der das Leere zeigt.

Danke für Eure Hilfe!

Noch kurz was: Kann ich aus der RegVar in eine Variable auch direkt HEX übergeben? Habe ich nirgends gefunden!
Gruß,
Matthias

Hier auch noch was zum „Gucken“…: