PHP + Siemens PLC

Ich möchte mal diesen Thread wieder zum Leben erwecken und eine kleine Testseite Posten an der ich gearbeitet habe.
Hiermit wird das bit DB100.DBX0.0 gesetzt. Ihr müsst also vorher diese DB mit dem BIT anlegen.


sps.php
Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
    <head>
        <title>S7 PLC Testseite</title>
        <script src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
    </head>
    <body>        
        <h1>S7 PLC Testseite</h1>
        
        <input type='button' value='Ein / Aus' class='schalter' typ='DB' db='100' byte='0' bit='0' bit-value='1' />                

        <script>
        $(document).on('click', 'input.schalter', function() {
            var typ = $(this).attr('typ');
            var db = $(this).attr('db');
            var byte = $(this).attr('byte');
            var bit = $(this).attr('bit');
            var bitval = $(this).attr('bit-value');            
            $(document).load('plc.php?function=bit', {'typ':typ, 'db':db, 'byte':byte, 'bit':bit, 'bit-value':bitval});
            $(this).attr('bit-value', bitval^1);    // xor bit to toggle value            
        });
        </script>
        
        <br /><br />
        
        <input type='button' value='Ein' class='taster' typ='DB' db='100' byte='0' bit='0' bit-value='1' />
        <input type='button' value='Aus' class='taster' typ='DB' db='100' byte='0' bit='0' bit-value='0' />                

        <script>
        $(document).on('click', 'input.taster', function() {
            var typ = $(this).attr('typ');
            var db = $(this).attr('db');
            var byte = $(this).attr('byte');
            var bit = $(this).attr('bit');
            var bitval = $(this).attr('bit-value');            
            $(document).load('plc.php?function=bit', {'typ':typ, 'db':db, 'byte':byte, 'bit':bit, 'bit-value':bitval});
            $(this).attr('bit-value', bitval);    // xor bit to toggle value            
        });
        </script>        
    </body>
</html>


plc.php
Code:
<?php
    include_once ("s7plc.php");

    $PLC_IP = "0.0.0.0"; // IP-Adresse der SPS
    $plc = new S7PLC("S7300", $PLC_IP, 0, 2, "TestPLC");

    try {
        if ($plc->Open() == 0) {            
            if ($_GET['function'] == 'bit') {            
                // Write Bits
                $typ = isset($_POST["typ"]) ? $_POST["typ"] : 0;
                $db = isset($_POST["db"]) ? $_POST["db"] : 0;
                $byte = isset($_POST["byte"]) ? $_POST["byte"] : 0;
                $bit = isset($_POST["bit"]) ? $_POST["bit"] : 0;    
                $bitval = isset($_POST["bit-value"]) ? $_POST["bit-value"] : 0;
                $plc->WriteBit($typ, $db, $byte, $bit, $bitval);  
            }
        } else {
            echo "<p>Konnte keine Verbindung zur SPS (IP:".$PLC_IP.") aufbauen!</p>\n";
        }
    } catch (Exception $e) {
        echo "<p>Konnte keine Verbindung zur SPS (IP:".$PLC_IP.") aufbauen!</p>\n";
    }
?>



Ich versuche immer noch verzweifelt ein einzelnes BIT auszulesen zwecks rückmeldungen. Wenn mir da jemand behilflich sein kann wäre das super!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
In der Klasse siehst du eine Funktion ReadBits glaube ich, die musst du mit in deine PHP einbauen.
Das setzen würde ich mittels AJAX Request machen, damit du eine Antwort der PHP Datei bekommen kannst.

Zum auslesen habe ich auf der Arbeit ein Beispiel, ich kann dir in wenigen Stunden etwas schicken.

Gruß mok
 
Da gibt es leider nur eine ReadBytes Function.

Und genau so mache ich es doch? Setzen mit JQuery und wenn ich eine rückmeldung haben möchte ob das bit gesetzt ist oder nicht kann ich mir das auch anzeigen lassen. Oder geht es mit AJAX noch einfacher?

Aber ich würde gerne mal dein Beispiel sehen!


MfG
 
Zuletzt bearbeitet:
Richtig, in der Klasse gibt es kein ReadBit. Sorry wollte oben ReadBytes schreiben.

Du kannst so z.B. einen Ausgang lesen
Code:
$plc = new S7PLC('S7400', 'xxx.xxx.xxx.xxx', 0, 3, 'S400 Test');
$plc->Open();
$plcdata = $plc->ReadBytes('A', 0, 81, 1);
$plc->Close();

$byte = ascii_to_bin($plcdata);
$bit = substr($byte, 0, 1);

echo $bit;

Genau so funktioniert es auch mit DBs. Du musst halt das Byte auslesen und dann dir das Bit rausziehen, oder du erweiterst die Klasse um ReadBit.

Um jetzt mit jQuery etwas zu senden und zu empfangen nutzt du einfach:

Code:
$.post("deine.php", {bit: 1}, function(data) {         
//alles was du in der php Datei ausgibst landet in data

alert(data);
//kannst du auch schön in der php Dateu als json konvertieren und mit "data = $.parseJSON(data);" hier parsen.

});

Wenn du noch fragen hast, frag ruhig!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Im Moment benutze ich noch JQuery um die Bits zyklisch auszulesen. In diesem Beispiel alle 250ms.

Code:
$(document).ready(function() {   
                loadData(); 

                function loadData() {            
                $('#output').load('plc.php?function=read-bit', { 'datatyp':'A', 'db':0, 'byte':2, 'bit':0}, function() {
                    setTimeout(loadData, 250);
                });
                }            
            });

Ich habe bis jetzt keine effizientere Lösung gefunden bei der nicht zyklisch angefragt wird. Besser wäre es wenn der Wert einmal übermittelt wird sobald er geändert wurde. Aber wie ich das machen kann weiß ich noch nicht....
 
Ich würde das Konzept nochmal grundsätzlich überdenken, wenn man damit wirklich mehr machen will als nur 2-3 Werte zu lesen. Aber das habe ich in diesem Thread schon mehrmals kundgetan.

Ich würde es so machen, dass das serverseitige Skript auf Anfrage ein json-Datensatz mit den Daten eines kompletten DBs in der SPS zurückliefert.
Und zwar symbolisch, und nicht über Absolutadressierung.
Dazu muss die serverseite wissen, welchen DB und mit welcher Länge es lesen soll, und die die Daten zu interpretieren sind und welches Symbol sie bekommen.

Beispiel Konfiguration für die Serverseite, das ist sozusagen die Datenbasis:
Code:
[Datenbereich]
DbNummer;Start;AnzahlBytes
100;0;20

[Symbole]
Symbol; Typ; Byteoffset; Bitoffset
MesswertReal1; Real; 0; 0
MesswertReal2; Real; 4; 0
BitMeldung1; Bool; 8;0
BitMeldung2; Bool; 8;1
BitMeldung3; Bool; 8;2
ZustandInt1; Int; 10;0
ZustandInt2; Int; 12;0

Kommt nun eine Anfrage an den Server, wird immer der komplette Datenbereich aus der SPS gelesen.
Dann interpretiert er die Daten anhand der Symbole, und schickt die Daten als json-Datensatz an den Client zurück.
Ob man dann alle Daten zurückschickt oder nur die angeforderten Symbole muss man dann entscheiden.
Man kann auch zwei Methoden wie ReadAll() oder Read("Symbol1", "Symbol") usw. schreiben.

Als Antwort kommt dann als json-Datensatz sowas wie:
Code:
{
  "MesswertReal1": 2.5,
  "MesswertReal1": 123.4,
  "BitMeldung1" : true,
  "BitMeldung2" : false,
  "BitMeldung3" : false, 
  "ZustandInt1" : 123,
  "ZustandInt2" : 456
}

Auf die Daten kann man dann komfortabel zugreifen.

Das Schreiben auf Datenbereiche erfolgt ebenfalls vom Client aus über die entsprechenden Symbole.


Noch besser wird es wenn man den php-Krams beiseite lässt, und einen eigenen Webservice schreibt welcher die Verbindung zur SPS auch über mehrere Anfragen offen halten kann, diese zyklisch pollt, und die Daten dann über sowas wie json-rpc abrufbar macht. Der könnte auch das von dir vorgeschlagene Sitzungs-Handling machen.
Das ist dann sowas wie ein OPC-XML-Server, nur ohne XML/Soap-Bloat ;-)
 
Ich müsste dann aber in deinem Beispiel manuell eine Anfrage senden, erst dann würde der Datensatz gelesen und kann dann von mir weiterverarbeitet werden.
Eine "Simple" Real-Time lösung gibt es nicht? Wo zb ein Byte ausgelesen wird sobald es geändert wurde?

Mein JQuery script funktioniert ja so wie ich es will, nur weiß ich nicht ob das den Webserver und/oder die SPS stark belastet....
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das Hauptproblem ist dass das serverseitige php-Skript nur für die Dauer einer Anfrage vom Client "lebt".

Das heißt eine Anfrage an den Server zieht jedes Mal folgendes nach sich:
1) TCP-Verbindung aufbauen
2) S7-Verbindung aufbauen
3) Eigentliche Daten aus der SPS lesen
4) Verbindung abbauen

Ob man das rein mit php anders lösen kann weiß ich nicht, bisher kam auf jeden Fall keine Lösung dazu.
Nichtsdestotrotz funktioniert das, man muss sich nur im Klaren sein dass es nicht die beste Lösung ist.
Dafür ist sie rein in php, und das war die Frage in diesem Thread.

Wenn ich eine webbasierende Lösung für eine S7 aufsetzen sollte, würde ich es so wie ich es oben geschrieben habe machen. Das wäre sogar unabhängig von der Steuerung verwendbar.
 
Ich habe mal einen kleinen Zusatz für die s7plc-Klasse programmiert, nach dem Schema was ich in #107 vorgeschlagen hatte.

Für die Konfiguration gibt es drei CSV-Dateien:
1) Stationskonfiguration mit Name, Ip-Adresse, Rack und Slot
2) Blockkonfiguration: Das sind die Blöcke die aus der SPS gelesen werden sollen. Ein Block kann maximal 222 Bytes groß sein
3) Tagliste: Hier werden die symbolschen Tagnamen aufgelistet. Die Adressen beziehen sich auf die Offsets der Blockkonfiguration

Bei einer Anfrage werden alle Tags der Tagliste abgefragt und die Daten als json-Datensatz zurückgegeben.
Schreiben funktioniert ebenfalls über json-Datensatz.

In der Demo gibt es eine Testseite in der alle konfigurierten Tags abgefragt werden und die Daten in einer Tabelle aufgelistet werden. Es können auch in der Tabelle Werte geschrieben werden.

Benötigt man nur eine einfache Liste um sich ein paar Werte anzusehen oder einzustellen, muss nur noch parametriert werden, d.h. die Einträge in den csv-Dateien anpassen.

Wenn man sich auf seinem Android-Gerät einen Webserver installiert (gibts als App), kann man das Ganze direkt auf seinem Smartfon/Tablet etc. laufen lassen.

Für Bavilo ist auch eine Bit-Auslese Funktion enthalten ;-)

Das Programm ist nur als - wenn auch funktionsfähiges - Beispiel zu verstehen! Die Verwendung erfolgt auf eigene Gefahr!

screenshot_tagliste.png
 

Anhänge

  • s7plc_db-2014-05-02.zip
    8,6 KB · Aufrufe: 129
Ich habe mal einen kleinen Zusatz für die s7plc-Klasse programmiert, nach dem Schema was ich in #107 vorgeschlagen hatte.

Für die Konfiguration gibt es drei CSV-Dateien:
1) Stationskonfiguration mit Name, Ip-Adresse, Rack und Slot
2) Blockkonfiguration: Das sind die Blöcke die aus der SPS gelesen werden sollen. Ein Block kann maximal 222 Bytes groß sein
3) Tagliste: Hier werden die symbolschen Tagnamen aufgelistet. Die Adressen beziehen sich auf die Offsets der Blockkonfiguration

Bei einer Anfrage werden alle Tags der Tagliste abgefragt und die Daten als json-Datensatz zurückgegeben.
Schreiben funktioniert ebenfalls über json-Datensatz.

In der Demo gibt es eine Testseite in der alle konfigurierten Tags abgefragt werden und die Daten in einer Tabelle aufgelistet werden. Es können auch in der Tabelle Werte geschrieben werden.

Benötigt man nur eine einfache Liste um sich ein paar Werte anzusehen oder einzustellen, muss nur noch parametriert werden, d.h. die Einträge in den csv-Dateien anpassen.

Wenn man sich auf seinem Android-Gerät einen Webserver installiert (gibts als App), kann man das Ganze direkt auf seinem Smartfon/Tablet etc. laufen lassen.

Für Bavilo ist auch eine Bit-Auslese Funktion enthalten ;-)

Das Programm ist nur als - wenn auch funktionsfähiges - Beispiel zu verstehen! Die Verwendung erfolgt auf eigene Gefahr!

Anhang anzeigen 24091


Was soll den Qualität darstellen?
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Was soll den Qualität darstellen?

Das ist die Signalqualität in Anlehnung an den Quality Code von OPC. Wenn die Daten aus der SPS nicht gelesen werden konnten ist der Signalzustand BAD, wenn gelesen werden konnte dann GOOD. Bei OPC ist der Zustand ein 16-Bit Wert in dem noch mehr Zustände einmaskiert werden können, ich habs der einfachheit halber auf zeri Test-Werte beschränkt. Den Wert könnte man z.B. nutzen um einen Ausgabewert bei ungültigem Zustand entsprechend zu kennzeichen. Sonst hättest du ja keine Möglichkeit zu sehen, ob der Wert 0 oder false ein gültiger Wert ist oder nicht.
 
Achso!

Gut ich muss sagen das ich nicht wie wahrscheinlich die meisten hier, recht wenig mit intensiver Programmierung von SPSen zu tun habe. Während meiner Ausbildung musste ich zwar mit S5 und S7 Programmieren aber das was ihr macht, werde ich im Leben nicht machen müssen. Da ich aber günstig an die S7 Steuerungen ran komme möchte ich diese für eine zukünftige Hausautomation einsetzen. Da muss ich keine komplexen Werte auslesen :)

Aber trotzdem hat mir deine Lib viel viel weiter geholfen!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
JSON.parse: unexpected character

Hallo miteinander.

Sorry, dass ich diesen Thread wieder nach oben schiebe, aber ich möchte auch gerne den Code von Thomas_v2.1 aus dem Posting #110 -> http://www.sps-forum.de/hochsprachen-opc/32409-php-siemens-plc-11.html#post490998 <- ausprobieren.
Es gelingt mir leider nicht, da ein "JSON-Fehler" vorliegt. Im Firefox 35.0.1 meldet Firebug folgenden Fehler:

Code:
[FONT=fixedsys]SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

var data = JSON.parse(xmlhttp.responseText);
[/FONT][FONT=fixedsys]-----------^[/FONT]
Sogar meinen Internet-Explorer 11 habe ich aus dem Tiefschlaf geholt, aber auch dieser zeigt kein anderes Verhalten.
Die CSV-Dateien habe ich meinen Bedürfnissen angepasst, also IP-Adresse und Datenbereiche.
Ich besitze eine CPU315F-2PN/PD und habe keinen extra CP gesteckt.

Weiß jemand, wie man diesen Fehler bereinigt?

Gruß,
poppycock
 
Überprüfe mal was für Daten per Json zurückkommen. In Firebug kannst du das im Reiter "Konsole" sehen. Wenn du die Seite aktualisierst gibt es nach dem ersten Aufruf ein GET ... getTagConfig.
Da schaust du rein was dort für Daten enthalten sind.
 
Hallo Thomas_v2.1,

guter Tipp!
Ich habe wohl einen Socket-Fehler, denn ich bekomme die Meldung:
Code:
"<br /> <b>Fatal error</b>: Call to undefined function socket_create() in <b>s7plc.php</b> on line <b>115</b><br /> "
Liegt das vielleicht an meinem PHP-Webserver "QuickPHP", der als Portable-Version läuft?!
Vielleicht kann dieser Webserver nicht mit Sockets umgehen...

Gruß,
poppycock
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Funktioniert doch!

Hallo nochmal,

ja, es lag an QuickPHP. :-?

Hab gerade deine Dateien auf einen "richtigen" Webserver geladen, damit funktioniert es!
Vielen Dank für deine Programmierung der Webseiten.

Mal schauen, was alles damit möglich ist! :D

Gruß,
poppycock
 
Ansonsten hättest du auch Server2Go verwenden können. Dieses lässt sich auch ohne Installation und Einrichtung starten, und das Projekt hier funktioniert damit auf jeden Fall. Damit teste ich meistens.
 
Habe das gleiche Problem.
ich bekomme den Fehler:
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

Ich verwende Apache 2.0 und PHP 5.0.5. Die Extension "php_sockets.php" habe ich aktiviert und trotzdem bekomme ich immer wieder diese Meldung. Verwendet wird eine SPS7 CPU 400 auf Rack 0 Slot 3. Datenbaustein 4 mit DW 8
Im Script selbst habe ich folgendes hinterlegt:
$PLC_IP= "10.39.1.18"; // IP-Adresse der SPS
$Db_num_ints = 4; // Datenbausteinnummer eines DBs mit Integer-Werten
$Anz_ints = 6; // Anzahl der Integes-Werte
$Db_num_reals = 8; // Datenbausteinnummer eines DBs mit Real-Werten
$Anz_reals = 6; // Anzahl der Real-Werten
$plc = new S7PLC("S7400", $PLC_IP, 0, 3, "TestPLC");

Habt Ihr einen Vorschlag für mich?
Danke schonmal.

 
Zurück
Oben