Hi,
Ich habe mal in einem Script meine Versuche der letzten Woche mit PoKeys56E zusammen gefasst. Der Support des Herstellers Poscope kann man nur als vorbildlich bezeichnen. Probleme und Fragen wurden umgehend gelöst und beantwortet. Aber nicht nur das. Meine per Mail angefragten Wünsche in Bezug auf fehlende Modbus Funktionen wurden umgehend umgesetzt und befinden sich jetzt in der aktuellen Firmware. Wenn ich das richtig sehe, sind jetzt alle Funktionen des Devices per Modbus verfügbar. Ein paar Sachen konnte ich noch nicht testen, bin aber guter Dinge das alles funktionieren wird.
Wie in diesem Post bereits beschrieben, sind einige Funktionen nicht über die native IPS Modbus Instanz nutzbar. Ist aber nicht tragisch, da Modbus TCP simpel zu Scripten ist. Erklärungen über Modbus TCP finden sich hier und vor allem hier.
Bei Modbus sende ich von IPS über TCP einen Hex String mit einer Lese oder Schreib Anforderung. Die Antwort vom Device ist auch ein Hex String. Ich benutze ich die Transaktionsnummer (Byte 1 + 2) um die Anfrage an das Device und die Antwort vom Device zuordnen zu können. Ich habe willkürlich in dem Script folgende Definitionen verwendet.
Digitalport lesen = D1
Analogport lesen = A1
Counter lesen = C1
Sensor lesen = 11
Digitalport schreiben = D0
Counter schreiben = C0
Die Pinnummer kodiere ich im nächsten Byte als normalen Dezimalwert
Pin1 = 01, Pin2 = 02, … Pin10=10 (nicht 0A!!), Pin11 = 11, usw.
Die Transaktionsnummer wird immer vom Device am Anfang der Antwort mitgeliefert. Wenn meine Antwortsequenz z.B. mit C1 19 beginnt, kann ich genau sagen, dass die Antwort das Ergebnis für „Counter lesen von Pin 19“ ist!.
Im anhängendem Bild ist die IPS Konfiguration abgebildet. Ich brauche eine „Client Socket“ Instanz für die IP Verbindung zum PoKeys56E. (Port 502)
Die „Register Variable“ hat diesen „Client Socket PoKeys56E“ als übergeordnete Instanz sowie das „PoKeys56E“ Script als Ziel Skript definiert.
Das Ziel Script „PoKeys56E“ wird durch einen zyklischen Timer alle 10 Sekunden gestartet.
Durch den Timer bekommen ich im Script alle 10 Sekunden ein „TimerEvent“. Das TimerEvent nutze ich, um alle Werte, die ich benötige bzw. angeschlossen habe, vom Device zu requesten. Die entsprechenden Request Strings muss ich in der if($IPS_SENDER == „TimerEvent“) Schleife anpassen.
Alle Antworten vom Device landen in der if($IPS_SENDER == „RegisterVariable“) -Schleife. Hier kann durch eine String Analyse die Art der Antwort, der angesprochenen Pin und der übermittelte Wert festgestellt werden. Diese Daten werden durch If und Case Schleifen separiert. Ich habe in dem Script ein Simples „Echo“ als Ausgabe verwendet. Man sieht die Ausgaben dadurch im Log. Anstelle des „Echo“ müsste dann z.B. eine Zuweisung des Wertes zu einer IPS Variablen vorgenommen werden. Da durch die freie Zuordnung der 55 Pins unzählige Variationen möglich sind habe ich nicht alle Fälle aufgeführt. Wenn ich z.B. die Pins 19-55 nicht nutze, brauche ich sie auch nicht in die Case Schleife aufnehmen.
In die if($IPS_SENDER == „Execute“) - Schleife habe ich ein paar Beispiele zum Beschreiben des Devices eingefügt. Bei manuellem Ausführen des Scriptes werden sie ausgeführt. Diese Befehle machen dort keinen praktischen Sinn und müssten in entsprechenden Aktionsscripte ausgelagert werden.
Ich hoffe, dass ich ich das Prinzip verständlich erklärt habe. Beispiele für das Auslesen von 1Wire und I2C habe ich in den unten stehenden Code hinzugefügt. Ich habe es aber erst nur mit 1Wire und nicht mit I2C Sensoren getestet. Das Sensoren auslesen über Modbus funktioniert allerdings erst mit Firmware 3.0.26. Wichtig ist hierbei auch die richtige Konfiguration der Modbus Berechtigung. Ohne Häkchen bei Read Access kann man die Sensoren nicht auslesen.
<?
$ClientSocket_ID = 23330 /*[Client Socket PoKeys56E]*/;
$RegisterVariable_ID = 37006 /*[Register Variable]*/;
define('DigitalRead01','D1 01 00 00 00 06 01 01 00 00 00 01');
define('DigitalRead02','D1 02 00 00 00 06 01 01 00 01 00 01');
define('DigitalRead03','D1 03 00 00 00 06 01 01 00 02 00 01');
define('DigitalRead04','D1 04 00 00 00 06 01 01 00 03 00 01');
define('DigitalRead05','D1 05 00 00 00 06 01 01 00 04 00 01');
define('DigitalRead06','D1 06 00 00 00 06 01 01 00 05 00 01');
define('DigitalRead07','D1 07 00 00 00 06 01 01 00 06 00 01');
define('DigitalRead08','D1 08 00 00 00 06 01 01 00 07 00 01');
define('DigitalRead09','D1 09 00 00 00 06 01 01 00 08 00 01');
define('DigitalRead10','D1 10 00 00 00 06 01 01 00 09 00 01');
define('DigitalRead11','D1 11 00 00 00 06 01 01 00 0A 00 01');
define('DigitalRead12','D1 11 00 00 00 06 01 01 00 0B 00 01');
//define('DigitalReadxx','...
define('AnalogRead41','A1 41 00 00 00 06 01 04 00 0A 00 01');
define('AnalogRead42','A1 42 00 00 00 06 01 04 00 0B 00 01');
define('AnalogRead43','A1 43 00 00 00 06 01 04 00 0C 00 01');
define('AnalogRead44','A1 44 00 00 00 06 01 04 00 0D 00 01');
define('AnalogRead45','A1 45 00 00 00 06 01 04 00 0E 00 01');
define('AnalogRead46','A1 46 00 00 00 06 01 04 00 0F 00 01');
define('AnalogRead47','A1 47 00 00 00 06 01 04 00 10 00 01');
define('CounterRead01','C1 01 00 00 00 06 01 03 03 20 00 02');
define('CounterRead02','C1 02 00 00 00 06 01 03 03 22 00 02');
define('CounterRead05','C1 05 00 00 00 06 01 03 03 28 00 02');
define('CounterRead06','C1 06 00 00 00 06 01 03 03 2A 00 02');
define('CounterRead09','C1 09 00 00 00 06 01 03 03 30 00 02');
define('CounterRead11','C1 11 00 00 00 06 01 03 03 34 00 02');
//define('CounterReadxx','...
define('SensorRead01','11 01 00 00 00 06 01 03 01 90 00 02'); //I2C Sensors
define('SensorRead02','11 02 00 00 00 06 01 03 01 92 00 02');
define('SensorRead03','11 03 00 00 00 06 01 03 01 94 00 02');
define('SensorRead04','11 04 00 00 00 06 01 03 01 96 00 02');
define('SensorRead05','11 05 00 00 00 06 01 03 01 98 00 02');
define('SensorRead06','11 06 00 00 00 06 01 03 01 9A 00 02');
define('SensorRead07','11 07 00 00 00 06 01 03 01 9C 00 02');
define('SensorRead08','11 08 00 00 00 06 01 03 01 9E 00 02');
define('SensorRead09','11 09 00 00 00 06 01 03 01 A0 00 02');
define('SensorRead10','11 10 00 00 00 06 01 03 01 A2 00 02');
define('SensorRead11','11 11 00 00 00 06 01 03 01 A4 00 02'); //1Wire Sensors
define('SensorRead12','11 12 00 00 00 06 01 03 01 A6 00 02');
define('SensorRead13','11 13 00 00 00 06 01 03 01 A8 00 02');
define('SensorRead14','11 14 00 00 00 06 01 03 01 AA 00 02');
define('SensorRead15','11 15 00 00 00 06 01 03 01 AC 00 02');
define('SensorRead16','11 16 00 00 00 06 01 03 01 AE 00 02');
define('SensorRead17','11 17 00 00 00 06 01 03 01 B0 00 02');
define('SensorRead18','11 18 00 00 00 06 01 03 01 B2 00 02');
define('SensorRead19','11 19 00 00 00 06 01 03 01 B4 00 02');
define('SensorRead20','11 20 00 00 00 06 01 03 01 B6 00 02');
define('DigitalWrite01','D0 01 00 00 00 06 01 05 00 00'); // + FF 00 -> on + 00 00 -> off
define('DigitalWrite02','D0 02 00 00 00 06 01 05 00 01');
define('DigitalWrite03','D0 03 00 00 00 06 01 05 00 02');
define('DigitalWrite04','D0 04 00 00 00 06 01 05 00 03');
define('DigitalWrite05','D0 05 00 00 00 06 01 05 00 04');
define('DigitalWrite06','D0 06 00 00 00 06 01 05 00 05');
define('DigitalWrite07','D0 07 00 00 00 06 01 05 00 06');
define('DigitalWrite08','D0 08 00 00 00 06 01 05 00 07');
define('DigitalWrite09','D0 09 00 00 00 06 01 05 00 08');
define('DigitalWrite10','D0 10 00 00 00 06 01 05 00 09');
define('DigitalWrite11','D0 11 00 00 00 06 01 05 00 0A');
define('DigitalWrite12','D0 12 00 00 00 06 01 05 00 0B');
define('DigitalWrite13','D0 13 00 00 00 06 01 05 00 0C');
//define('DigitalWritexx','...
define('CounterWrite01','C0 01 00 00 00 0B 01 10 03 20 00 02 04'); // + 4 Byte value LSB/MSB
define('CounterWrite02','C0 02 00 00 00 0B 01 10 03 22 00 02 04');
define('CounterWrite05','C0 05 00 00 00 0B 01 10 03 28 00 02 04');
define('CounterWrite06','C0 06 00 00 00 0B 01 10 03 2A 00 02 04');
define('CounterWrite09','C0 09 00 00 00 0B 01 10 03 30 00 02 04');
define('CounterWrite11','C0 11 00 00 00 0B 01 10 03 34 00 02 04');
//define('CounterWritexx','...
function strtohex($string) {
$hexstr = unpack('H*', $string);
return strtoupper(array_shift($hexstr));
}
function hextostr($hex) {
$str='';
$hex = str_replace(' ', '', $hex);
for ($i=0; $i < strlen($hex)-1; $i+=2) {
$str .= chr(hexdec($hex[$i].$hex[$i+1]));
}
return $str;
}
function dechex_lsb_msb($decvalue) {
$hexstr=dechex($decvalue);
for ($i = strlen($hexstr); $i < 8; $i++) {
$hexstr="0".$hexstr;
}
return substr($hexstr, 4, 4).substr($hexstr, 0, 4);
}
function status_hex ($status) {
if($status == 1) {
return "FF 00";
} else {
return "00 00";
}
}
function modbus_send($ID, $hex) {
RegVar_SendText($ID, hextostr($hex));
IPS_Sleep(10);
}
if($IPS_SENDER == "TimerEvent") {
// Reconnect Client Socket. Not needed for timer cycles below the configured Modbus timeout
IPS_ApplyChanges($ClientSocket_ID);
// send the read request strings of the needed values
modbus_send($RegisterVariable_ID, DigitalRead01);
modbus_send($RegisterVariable_ID, DigitalRead02);
//..
modbus_send($RegisterVariable_ID, AnalogRead41);
modbus_send($RegisterVariable_ID, AnalogRead42);
//..
modbus_send($RegisterVariable_ID, CounterRead01);
modbus_send($RegisterVariable_ID, CounterRead02);
//..
modbus_send($RegisterVariable_ID, SensorRead11);
modbus_send($RegisterVariable_ID, SensorRead12);
//..
}
if($IPS_SENDER == "RegisterVariable") {
$hexstring = strtohex($IPS_VALUE);
$arr_modbus_receive = str_split(strtohex($IPS_VALUE), 2);
if($arr_modbus_receive[0] == "D1") { // D1 -> Modbus answer for digital read
// read the status of the PIN
if($arr_modbus_receive[9] == "01") {
$value = 1;
} else {
$value = 0;
}
// Assign status to
switch ($arr_modbus_receive[1]) {
case "01":
echo "Digital In Pin1 = ".$value."
";
break;
case "02":
echo "Digital In Pin2 = ".$value."
";
break;
}
}
if($arr_modbus_receive[0] == "A1") { // A1 Modbus answer for analog read
$value = hexdec($arr_modbus_receive[9].$arr_modbus_receive[10]);
// 12bit 3.3V max -> $volt = $value * 3.3 / 4095
$volt = number_format($value * 3.3 / 4095, 3);
switch ($arr_modbus_receive[1]) {
case "41":
echo "Analog In Pin41 = ".$volt." V
";
break;
case "42":
echo "Analog In Pin42 = ".$volt." V
";
break;
case "43":
echo "Analog In Pin43 = ".$volt." V
";
break;
case "44":
echo "Analog In Pin44 = ".$volt." V
";
break;
case "45":
echo "Analog In Pin45 = ".$volt." V
";
break;
case "46":
echo "Analog In Pin46 = ".$volt." V
";
break;
case "47":
echo "Analog In Pin47 = ".$volt." V
";
break;
}
}
if($arr_modbus_receive[0] == "C1") { // C1 Modbus answer for counter read
$hex = $arr_modbus_receive[11].$arr_modbus_receive[12].$arr_modbus_receive[9].$arr_modbus_receive[10];
$dec = hexdec($hex);
$max = pow(2, 4 * (strlen($hex) + (strlen($hex) % 2)));
$_dec = $max - $dec;
if($dec > $_dec) {
$value = -$_dec;
} else {
$value = $dec;
}
switch ($arr_modbus_receive[1]) {
case "01":
echo "Counter Read Pin1 = ".$value."
";
break;
case "02":
echo "Counter Read Pin2 = ".$value."
";
break;
case "05":
echo "Counter Read Pin5 = ".$value."
";
break;
case "06":
echo "Counter Read Pin6 = ".$value."
";
break;
}
}
if($arr_modbus_receive[0] == "11") { // 11 Modbus answer for sensor read
$hex = $arr_modbus_receive[11].$arr_modbus_receive[12].$arr_modbus_receive[9].$arr_modbus_receive[10];
$dec = hexdec($hex);
$max = pow(2, 4 * (strlen($hex) + (strlen($hex) % 2)));
$_dec = $max - $dec;
if($dec > $_dec) {
$value = -$_dec;
} else {
$value = $dec;
}
// Temperature convert
$value = $value / 100;
switch ($arr_modbus_receive[1]) {
case "01":
echo "Sensor01 Read = ".$value." °C
";
break;
case "02":
echo "Sensor02 Read = ".$value." °C
";
break;
case "11":
echo "Sensor11 Read = ".$value." °C
";
break;
case "12":
echo "Sensor12 Read = ".$value." °C
";
break;
}
}
if($arr_modbus_receive[0] == "D0") { // D0 -> Modbus answer for digital write
// read the status of the PIN
$hexstr = strtoupper($arr_modbus_receive[10].$arr_modbus_receive[11]);
if($hexstr == "FF00") {
$status = 1;
} else {
$status = 0;
}
// Assign status to Pin
switch ($arr_modbus_receive[1]) {
case "01":
echo "Set Digital Out Pin1 = ".$status."
";
break;
case "02":
echo "Set Digital Out Pin2 = ".$status."
";
break;
case "03":
echo "Set Digital Out Pin3 = ".$status."
";
break;
case "04":
echo "Set Digital Out Pin4 = ".$status."
";
break;
//case...
}
}
if($arr_modbus_receive[0] == "C0") { // C0 Modbus answer for counter write
switch ($arr_modbus_receive[1]) {
case "01":
echo "Set Counter Value Pin1
";
break;
case "02":
echo "Set Counter Value Pin2
";
break;
//case ...
}
}
}
if($IPS_SENDER == "Execute") {
// Reconnect Client Socket.
IPS_ApplyChanges($ClientSocket_ID);
//here are some write examples
// Set Digital Output Pin3 to on = 1
modbus_send($RegisterVariable_ID, DigitalWrite03.status_hex(1));
// Set Digital Output Pin4 to off = 0
modbus_send($RegisterVariable_ID, DigitalWrite04.status_hex(0));
// Set Counter value of Pin 1 to 123456789
modbus_send($RegisterVariable_ID, CounterWrite01.dechex_lsb_msb(123456789));
// Set Counter value of Pin 2 to -111
modbus_send($RegisterVariable_ID, CounterWrite02.dechex_lsb_msb(-111));
}
?>