PHP + Siemens PLC

Zuviel Werbung?
-> Hier kostenlos registrieren
Warning: socket_read() [function.socket-read]: unable to read from socket [0]: Ein nicht blockierender Socketvorgang konnte nicht sofort ausgeführt werden.
in C:\webroot\S7\s7plc.php on line 193

Hier hat schon mal jemand etwas zu dem Thema geschrieben.
http://computer.wer-weiss-was.de/php/php-socketserver-mag-nonblocking-nicht

Was macht
s7plc.php on line 193
denn so?
 
In der Zeile 193 steht:
191: socket_write($this->mSocket, $msg, strlen($msg));
192: $buf = "";
193:
$buf = socket_read($this->mSocket, 22);
 
Hallo zusammen,
danke erst einmal für diese tolle Implementation.

Ich habe hier eine S7-1200 bei der ich den Ausgang A1.1 auslese:
Code:
$plc = new S7PLC('S7400', '192.168.130.71', 0, 1, 'Test');
$plc->ReadBytes('A', 0, 1, 1);

Funktioniert super. Nun habe ich eine weitere S7-1200, welche ich genau so auslese, natürlich mit andere IP:
Code:
$plc = new S7PLC('S7400', '192.168.130.75', 0, 1, 'Test');
$plc->ReadBytes('A', 0, 1, 1);

Hier bekomme ich keinerlei Rückgabe von der Funktion "ReadBytes", nur die Fehlermeldung:
Code:
Notice: Uninitialized string offset: 21 in /var/www/html/test/s7plc_db/s7plc.php on line 290

Die erste SPS hat die Firmware V3.0, die zweite V4.1 - könnte es vielleicht daran liegen?
Muß ich eventuell erst den Zugriff erlauben?

lg
Frank
 
Bim mir ziemlich sicher dass du bei der CPU unter Hardware / Schutz / Verbindungsmechanismen den
"Zugriff über PUT/GET-Kommunikation durch entfernten Partner (PLC, HMI, OPC, ...) erlauben"
manuell aktivieren musst.

Das ist zwischen v3 und v4 unterschiedlich.
 
Zuletzt bearbeitet:
Sorry, jetzt muß ich doch noch mal fragen:

Ich habe einen Datenbaustein Datenbaustein_1[DB1]:
Zeile 1 ist mit "Static" benannt, darunter befinden sich 20 Einträge.
Es werden die Typen Time, Byte, UDInt und Word verwendet.
Mit der Abfrage
Code:
$plc->ReadBytes('DB', 1, 0, 20);
erhalte ich leider keine Werte. Was mache ich falsch?

Im Parameter-Teil des Telegramms gibt es Time, UDInt nicht (s7plc.php Zeile 31 ff)

lg
Frank
 
So, bin etwas weiter gekommen:

Der Datenbaustein ist mit "optimierten Bausteinzugriff". Damit symbolisch und nicht direkt adressierbar.
Habe nun einen 2. Datenbaustein (DB23) angelegt ohne optimierten Bausteinzugriff.

Für 0.0 habe ich den Typ DInt angelegt und den Wert 1234 gesetzt. Ich lese vom DB23 an Adresse 0 für DInt (4 bytes) aus:
Code:
$plcdata = $plc->ReadBytes('DB', 23, 0, 4);
mittels der Funktion ascii_to_bin erhalte ich:
00000000 00000000 00000100 00111111 was aber Dezimal 1078 entspricht und nicht wie erwartet 1234

Was könnte da schief gehen?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Für 0.0 habe ich den Typ DInt angelegt und den Wert 1234 gesetzt. Ich lese vom DB23 an Adresse 0 für DInt (4 bytes) aus:
Code:
$plcdata = $plc->ReadBytes('DB', 23, 0, 4);
mittels der Funktion ascii_to_bin erhalte ich:
00000000 00000000 00000100 00111111 was aber Dezimal 1078 entspricht und nicht wie erwartet 1234
Das letzte Bit ist 1 --> ungerade Zahl! :cool: Es kann also nicht 1234 sein, aber auch nicht 1078. Es entspricht tatsächlich 1087 dezimal.

Wozu wandelst Du mit der Funktion ascii_to_bin? Ohne Wandlung solltest Du 1234 erhalten.
Kannst Du beobachten, daß in DB23.DBD0 tatsächlich 1234 dezimal drinsteht? Vielleicht hast Du Überschneidungen und irgendwo wird das DBW2 überschrieben?

Harald
 
Du hast vollkommen Recht, hatte einen Zahlendreher, die Ausgabe ist 1087.

Das Script sieht nun so aus;

Code:
<?
include("s7plc.php");

$plc = new S7PLC('S7400', '192.168.130.75', 0, 1, 'Test');
$plc->Open();

echo $plc->ReadBytes('DB', 23, 0, 4);

$plc->Close();
?>

Der Datenbaustein:
DB23.jpg

Als Augabe erhalte ich mit diesem Script im Browser: Ò


Der Datenbaustein ist autark, vom Programm aus wird weder gelesen noch geschrieben.
Ich schreibe die 1234 per "Operand steuern".
Wie finde ich heraus, ob es Überschneidungen gibt? Sorry für die dumme Frage, ich wechsel gerade von 10 Jahren S7-200 auf die 1200er.

lg und Danke für die Hilfe,
Frank
 
In irgendeiner Version hier im Thread waren auch diverse Konvertierungsfunktionen enthalten, um die Werte aus dem Ergebnis-String zu extrahieren.

Für DINT sollte es sowas sein:
Code:
function getS32At($str, $pos)
{
	$val = unpack("l", $str[$pos + 3] . $str[$pos + 2] . $str[$pos + 1] . $str[$pos]);
	return $val[1];	
}

Aufrufen dann z.B. mit:
Code:
$data = $plc->ReadBytes('DB', 23, 0, 4);
$wert = getS32At($data, 0);

Das sollte dann der Wert von DB23.DBD0 als vorzeichenbehafteter Integerwert sein.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Juhu, mit der Konvertierungsfunktion kommt der korrekter Wert nun.
Danke, danke, danke.

Dass dies ein Binärstring ist, warum bin ich da nicht selber drauf gekommen?

Danke nochmals, liebe Grüße
Frank
 
Hello guys,

I'm not a plc programmer nor a pc programmer (just a "power"-electrician) so this might be a newbie question for this forum (but i still remember some plc&pc programming from a long time ago):

For my domotica at home I used this for example for a light controlled with one pushbutton:

dom.jpg

Now my question:

Do i HAVE TO work with data blocks to read and send my I/O via ethernet on my php-server?
If yes: how would you program it into your plc?
I suppose like this:

dom2.jpg
Now the question: how would you edit the config_blocks.csv and the config_tags.csv files to make this particular one-pushbutton-light working?

And if i DO NOT HAVE to use DataBlocks to read/write my I/O: How would you edit the .csv and/or .php files to make this particular function work?

Sorry for my english confusion but my German language is even far worse ;-)
 
Zuletzt bearbeitet:
I would recommend to use datablocks, because then you have a defined interface between the program and the HMI.
You can use the datablock address in the same manner as you have used the digital input.
For example, if you use DB1 for HMI interface, and you add at address DBX0.0 a command to toogle the light, then you could replace I0.0 with DB1.DBX0.0 and it should work.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Thank you that works really nice :)


Is there an easy way to just read/write a bool/bit in the DB1? (without using AJAX or JSON or any complicated PHP stuff ;-))

something like:


Code:
<html>
 <head>
  <title>PHP Test</title>
 </head>
 <body>
 
 <?php
 include 's7plc.php';
 echo "The current state of this light is: " ReadBytes( "DB", "1", "0", "0");
 echo "<a href='' onclick=" WriteBit( 'DB', '1', '0', '0', '1') ">Switch light on</a>";
 ?>
 
 </body>
</html>
 
Zuletzt bearbeitet:
thanks the WriteBit function worked out of the box
the ReadBytes function i had to add this middle line to s7plc.php:

Code:
$recv = substr ($recv,  $offs + 25);
$recv = str_pad(decbin(ord($recv)),8, "0", STR_PAD_LEFT);
return $recv;
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Zusammen,

ich habe leider ein Problem mit dem Script (S7sps.php) von Thomas Wiens (Version vom 20.1.2010).

Auslesen und schreiben von Bits klappt wunderbar. Habe nur ein Problem Bytes zu schreiben wenn ich einen "Value" übergebe schreib er den Zahlenwert auch in das angegebene Byte.

Aber, leider schreibt er nur bis zur Zahl 9 (also die ersten 4 Bits). Im zweiten Bit Paket (4-7) beschreibt er einfach mal das Bit 4 und 5 auch wenn ich nur eine "1" übergebe.

z.B.

Wert = 1 = 00110001

Wert = 9 = 00111001

Wert = 10 = 00110001

Hab schon ein paar Sachen im Script (S7sps.php) ausprobiert. Aber konnte leider nichts erreichen.

Vielleicht kann mir ja hier jemand weiterhelfen?
 
Wie packst du die Daten denn in das Sendetelegramm? Wenn ich mich recht entsinne, hatte ich bisher nur Funktionen um 16 Bit Integer zu schreiben.

Du brauchst zwei passende Funktionen die auch nur ein 8-Bit Integer schreiben, wie
Code:
function putU8($val)
{
	$str = pack("C", $val);
	return $str;
}

function getU8At($str, $pos)
{
	$val = unpack("C", $str[$pos]);
	return $val[1];
}

und dann schreiben mit
Code:
$write_packet = "";
$write_packet .= putU8(100);
$write_packet .= putU8(200);
$plc->WriteBytes("DB" , 1, 0, $write_packet);
schreibt 100 an DB1.DBB0 und 200 an DB2.DBB1.

Das funktioniert.
 
Danke für die schnelle Antwort!!

Wenn du der Autor dieses Scripts bist, muss ich dir auch erstmal danke. Bin gerade erstmal richtig damit am arbeiten aber läuft wirklich super und ist für mich bis jetzt konkurrenzlos.

Wenn es auch mal eine neuere Version gibt bin ich sehr dran Interessiert.

Aber jetzt mal zum Problem.

Eigentlich wollte ich auch einen 16 Bit Integer schreiben :) Dachte aber die Funktion wäre hauptsächlich dafür gedacht einzelne Bytes zu schreiben.

Aaaaaber... Jetzt läuft es. Dank dir! Top. Vielen Dank!

Der Fehler war eigentlich ganz simpel. Bis jetzt musst ich mich noch nicht mit dem packen von Daten beschäftigen.

$sps_value = pack("n", $sps_value);
$wert = $plc->WriteBytes($sps_type, $sps_DB, $sps_byteadr, $sps_value);

Problem gelöst. Nochmals Danke!!
 
Zurück
Oben