Snap 7 Python Raspberry pi S7

emilio20

Level-1
Beiträge
835
Reaktionspunkte
20
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo

ich habe auf einem Raspberry pi Snap 7 installiert. Dies hat auch soweit funktioniert.
Ich habe mir ein kleinen Python Programm geschrieben das Daten von einer S7 liest und schreibt. Wenn ich die Zykluszeit auf 0.2 Sekunden stelle friert das Raspberry pi nach ca. 7 Stunden ein.
Bei 1 Sec läuft es länger. Ich benötige aber für den weiteren verlauf eine Zykluszeit von 0.2 sec.

Hat jemand erfahrung hiermit ?

Hier mal das Python Programm

Code:
from time import sleep
import snap7
from snap7.util import*
import struct


db = 390
length = 1
Start = 2

def main()

    while True:
        try:
            plc = snap7.client.Client()
            plc.connect("192.168.178.30",0,2)
            con = plc.get_connected()
            print "Connect", con

            byte = plc.db_read(390,2,1)
            print "Bit1:",get_bool(byte,0,0)
            print "Bit2:",get_bool(byte,0,1)
            print "Bit3:",get_bool(byte,0,2)
            print "Bit4:",get_bool(byte,0,3)
            print "Bit5:",get_bool(byte,0,4)


            data = bytearray(1) 
            set_bool(data,0,0,True)
            set_bool(data,0,1,True)
            set_bool(data,0,2,True)
            set_bool(data,0,3,True)
            set_bool(data,0,4,True)

            plc.db_write(390,0,data)
            plc.disconnect()
            sleep(0,2)
        except Exception as ex:
            print "Verbindungsfehler"
        
        
if __name__ == "__main__":
    main()
 
Zuletzt bearbeitet:
Ohne das selber schon verwendet zu haben würde ich folgendes anpassen:
Du erzeugst alle 0,2 Sekunden ein neues snap7.client Objekt, baust die Verbindung auf, liest Daten, Verbindung wieder abbauen und neues Objekt erzeugen.
Ich würde außerhalb der Schleife das Objekt nur einmal erzeugen und nur einmal die Verbindung aufbauen und dann für die Dauer in der du zyklisch Daten lesen willst, diese auch offen halten. Das geht wesentlich schneller, du hast weniger Netzwerklast und benötigt auch keine andauernd neuen Ressourcen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Thomas,
wenn ich es so mache habe ich das Problem das die Verbindung nach einem Verbindungsabbruch nicht mehr aufgebaut wird da "plc = snap7.client.Client()" auserhalb der "try": liegt ?

Code:
from time import sleep
import snap7
from snap7.util import*
import struct


db = 390
length = 1
Start = 2

def main()

    plc = snap7.client.Client()
    plc.connect("192.168.178.30",0,2)
    con = plc.get_connected()
    print "Connect", con

    while True:
        try:
            
            byte = plc.db_read(390,2,1)
            print "Bit1:",get_bool(byte,0,0)
            print "Bit2:",get_bool(byte,0,1)
            print "Bit3:",get_bool(byte,0,2)
            print "Bit4:",get_bool(byte,0,3)
            print "Bit5:",get_bool(byte,0,4)


            data = bytearray(1) 
            set_bool(data,0,0,True)
            set_bool(data,0,1,True)
            set_bool(data,0,2,True)
            set_bool(data,0,3,True)
            set_bool(data,0,4,True)

            plc.db_write(390,0,data)
            plc.disconnect()
            sleep(0,2)
        except Exception as ex:
            print "Verbindungsfehler"
        
        
if __name__ == "__main__":
    main()
 
Um es so einfach in deiner Endloschschleife zu behalten, könntest du den Verbindungszustand in einer Variable connected halten. Wenn connected dann kannst du über die Verbindung lesen. Wenn das Lesen fehlschlägt setzt du connected auf False und versuchst daraufhin die Verbindung neu aufzubauen, und wenn das funktioniert dann connected wieder auf True und weiterlesen.
 
Ich habe mal in der Beschreibung zu dem Modul nachgesehen. Es gibt für den snap7 client noch die Methode destroy() um Ressourcen freizugeben.
Du solltest darauf achten, plc = snap7.client.Client() nur einmal zu Beginn zu erstellen und nicht innerhalb deiner Poll-Schleife. Selbst wenn die Verbindung weg ist, kannst du versuchen dich mit connect erneut zu verbinden ohne ein neues Client Objekt anzulegen, denn das gibt es ja schon.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Thomas,
So werde ich es mal testen. Das destroy() habe ich unter " except Exception as ex:" gepackt. Hoffe das stimmt so ?

Code:
from time import sleep
import snap7
from snap7.util import*
import struct



def main()
    plc = snap7.client.Client()
    con = Flase
    while True:
        try:
            if con == False:
                plc.connect("192.168.178.30",0,2)
                con = plc.get_connected()
                print "Connect", con
                con = True

            byte = plc.db_read(390,2,1)
            print "Bit1:",get_bool(byte,0,0)
            print "Bit2:",get_bool(byte,0,1)
            print "Bit3:",get_bool(byte,0,2)
            print "Bit4:",get_bool(byte,0,3)
            print "Bit5:",get_bool(byte,0,4)


            data = bytearray(1) 
            set_bool(data,0,0,True)
            set_bool(data,0,1,True)
            set_bool(data,0,2,True)
            set_bool(data,0,3,True)
            set_bool(data,0,4,True)

            plc.db_write(390,0,data)
            sleep(0,2)
        except Exception as ex:
            print "Verbindungsfehler"
            con = False
            plc.disconnect()
            plc.destroy()         
        
if __name__ == "__main__":
    main()
 
Zuletzt bearbeitet:
destroy() würde ich aufrufen wenn die Verbindung nicht mehr benötigt wird. Snap7 unterstützt auch asynchrone Vorgänge, und mit destroy werden dann die laufenden Threads abgeräumt. Ich weiß aber nicht ob die Python Version davon etwas nutzt, schaden tut es auf jeden Fall nicht.

Ich würde es ja so programmieren, dass ich die Verbindung offen halte. Gerade wenn du so oft lesen willst ist das unsinnig die Verbindung andauernd zu schließen und wieder zu öffnen. Der Verbindungsauf- und abbau dauert vermutlich länger als das Lesen an sich.
Und wenn die Bibliothek schon eine Methode zum Feststellen des Verbindungszustands mitbringt, dann brauchst du eigentlich keine extra Variable.
 
Zuletzt bearbeitet:
Was sagt denn der Fehlertext warum es abbricht.
Printe bitte auch die exception (ex) oder lass das Try-Catch mal komplett weg um die Fehlerursache in der Ausgabe zu erhalten.

Ruf dein Programm mal mit ner Pipe auf um nen Error Log zu erhalten

Also z.B:

Code:
python siemens.py > siemens_error.log
/CODE]

Grüße

Marcel
 
Hallo
ich habe gestern schon einen Log eingebaut da steht nichts drinnen. Das Pi wird immer langsammer bis es schließlich nicht mehr läuft.

Hier mal der ganze Code. Der obere Code ist nur zum Test.

Ich könnte noch die Zykluszeit in eine log schreiben um zu sehen wann es langsammer wird.

Code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from time import sleep
from time import strftime
from datetime import datetime
import snap7
from snap7.util import*
import struct
import string
from time import*
import serial, time
from RPi import GPIO
import os
import sys

############################ Doorpi Datenpfad ###############################

# Datenpfat virtual Keyboard
Dateipfad_imput1 = '/var/DoorPI/keyboard/inputs/e1'
Dateipfad_output1 = '/var/DoorPI/keyboard/outputs/a1'


############################## Parameter SPS ################################
ip='192.168.178.30'     # IP Adrresse SPS
rack = 0
slot = 2
S7_DRead = [69,2,90]    #Adresse bit lesen aus SPS
S7_DWrite = [69,0]      # Adresse bit schreiben in SPS
plc = snap7.client.Client()


############################# Nextion Display ################################

EndCom = "\xff\xff\xff"
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
LCD_Display_Zeile = ["*","*","*","*","*"]


################################ GIPO Pins ###################################   
# Zählweise der Pins festlegen
GPIO.setmode(GPIO.BOARD)

# Pin 16 (GPIO 23) Bewegungsmelder als Eingang festlegen
PIR_PIN = 16
GPIO.setup(PIR_PIN, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)


################################ Logfile #################################### 
#Logfile Ordner
logfile = '/home/pi/S7/Log/logfile_'+time.strftime("%d.%m.%Y")+'.log'


############################## Funktionen ################################### 


def Write_V_Keyboard (value):
    try:
        
        f = open (Dateipfad_imput1 ,"w")
        v =str(value)
        f.write(v)
        f.close()
        
    except Exception as ex:
        print ("Fehlerm beim schreiben in Virtual Keyboard",ex)
        log("Fehlerm beim schreiben in Virtual Keyboard")
        sleep(5.0)
        


def Read_V_Keyboard(): 
    try:
        #print "Value aus Doorpi Virtual Keyboard lesen"
        f = open (Dateipfad_output1,"r")
        v = f.readline()
        f.close()
        BOOL = State_BOOL(v)
        return BOOL
    except Exception as ex:
        print ("Fehlerm beim lesen aus Virtual Keyboard",ex)
        log("Fehlerm beim lesen aus Virtual Keyboard")
        sleep(5.0)
        
        

def Nextion_Write_Text(serial_obj, input_str, Nr):
    try:
        #Nextion_Write(ser, 't0.txt='+'"'+LCD_Display_Zeile0+'"')
        Nex_str = 't'+str(Nr)+'.txt='+'"'+input_str+'"'
        serial_write = Nex_str + EndCom
        serial_obj.write(serial_write)
     
    except Exception as ex:
        print ("Fehler Display",ex)
        log("Fehler Display")
        sleep(5.0)

def Nextion_Write(serial_obj, input_str):
    try:
        serial_write = input_str + EndCom
        serial_obj.write(serial_write)
     
    except Exception as ex:
        print ("Fehler Display",ex)
        log("Fehler Display")
        sleep(5.0)


def Nextion_Dim(dim):
    Nextion_Write(ser, 'dim='+str(dim))
        
        


def State_BOOL(Value):
    if 'True'  in Value:
        BOOL = True
    else:
        BOOL = False
    return BOOL


def log(msg):
    #Log
  file = open(logfile,"a")
  file.write("%s: %s\n" % (time.strftime("%d.%m.%Y %H:%M:%S"), msg))
  file.close


  
##################### Hauptprogramm ##############################



def main():
                
        
    Verbindung = False
    con = False
    Bewegungsmelder = False
    Nextion_Licht = False
    DELTA = 5
    sleep(2.0)
    start = datetime.now()
    
    try:
    
        while True:
            try:
                
                
                if con == False: 
                    #print "Verbindungsaufbau"
                    plc.connect(ip,rack,slot)
                    con = plc.get_connected()
                    print "Connect", con
                    sleep(3.0)
                
                
                #print"lese Daten aus SPS"
                data = plc.db_read(S7_DRead[0],S7_DRead[1],S7_DRead[2])
                
                #schreibe Daten von SPS in Variablen
                Klingeltaster_1     = get_bool(data,0,0)
                print "Klingeltaster_1  ",Klingeltaster_1
                #Klingeltaster_2     = get_bool(data,0,1)
                #print "Klingeltaster_2  ",Klingeltaster_2
                LCD_Display_Zeile[0]  = get_string(data,2,22)
                LCD_Display_Zeile[1]  = get_string(data,24,22)
                LCD_Display_Zeile[2]  = get_string(data,46,22)
                LCD_Display_Zeile[3]  = get_string(data,68,22)

                
                #schreibe Daten (Klingeltaster_1) in Virtual Keyboard     
                Write_V_Keyboard(Klingeltaster_1)
                #schreibe Daten (Klingeltaster_2) in Virtual Keyboard     
                #Write_V_Keyboard(Klingeltaster_2)

                #print"lese Daten aus Virtual Keyboard"
                Tuer_Oeffner = Read_V_Keyboard()
                print "Tür Öffner       ",Tuer_Oeffner
                            
                #Schreibe Text in Display (Zeile 0-3)
                for i in range (0,4):
                    Nextion_Write_Text(ser,LCD_Display_Zeile[i],i)
                #sleep(0.3)
                #Bewegungsmelder auslesen
                Bewegungsmelder = GPIO.input(PIR_PIN)
                #print ('Bewegungsmelder   False' if Bewegungsmelder < 1 else 'Bewegungsmelder   True')
                
                #Nextion Display aufdimmen bei Bewegung
                if Bewegungsmelder == 1:
                    Nextion_Licht = True
                    action_time = datetime.now()
                    #print "Start_Time" , action_time
                    print "Licht an " ,Nextion_Licht
                    Nextion_Dim(100)
                        
                    
                #Ausschaltverzögerung Nextion Display Belechtung
                if Nextion_Licht and (datetime.now() - action_time).seconds > DELTA:
                    Nextion_Licht = False
                    print "Licht aus " ,Nextion_Licht
                    #print "Start_Time" , datetime.now()
                    #Nextion Display adimmen nach ablauf der Verzögerungszeit DELTA
                    Nextion_Dim(1)
                   
                                   
                #Verbindungssstatus Toggen
                if Verbindung == True:
                    Verbindung = False
                else:
                    Verbindung = True
                
                #print"schreibe Daten in Sendedatei"
                data_send = bytearray(2)
                set_bool(data_send,0,0,Verbindung,)
                set_bool(data_send,0,1,Tuer_Oeffner,)
                set_bool(data_send,0,2,Bewegungsmelder,)
                #set_bool(data_send,0,3,Stoerung,)
                #print "Störung", Stoerung
                    
                #print"Schreibe Daten in SPS"
                plc.db_write(S7_DWrite[0],S7_DWrite[1],data_send)
                     
                #Wartezeit
                sleep(0.2)
                os.system('cls')

            except Exception as ex:
                print ("Verbindungsfehler",ex)
                con = False
                plc.disconnect()
                plc.destroy()
                log(ex)
                sleep(10.0)

    except KeyboardInterrupt:
        print "GIPO cleanup"
        GPIO.cleanup()
        print "PLC disconnect"
        plc.disconnect()
        plc.destroy()
        print "Beende...."
        sys.exit(0)
           

if __name__ == "__main__":
    main()
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Und welches Programm lässt du jetzt dauerhaft laufen? Mach doch mal ein Minimalprogramm für snap7 ohne irgendwas anderes drumherum was du dauerhaft laufen lässt. Dann prüfen was passiert wenn du das Netzwerkkabel an verschiedenen Stellen ziehst, oder auch mal den DB in der SPS löschst usw.

Und nach dem destroy musst du soweit ich das sehe den Konstruktor neu aufrufen, in deinem Fall kannst du das auch kompett weglassen wenn die Verbindung immer aktiv sein soll.
 
Hallo Thomas,
wenn ich das Netzwerk abziehe Verbindet sich das Raspberry wieder wenn ich das Netzwerk anstecke. Das soll auch so sein. Das ist aber nicht das Problem.
Ich habe das minimale Programm als auch das komplette Programm getestet. Ergebnis beide Programm laufen nur ca. 7h bei 0,2 sec Zyklus. Das Komplette Programm Post 11 ohne den S7 teil läuft tagelang.
Aktuell teste ich mit 1 sec seid heute Morgen, Programm läuft noch.

Was ich noch machen will snap7-full-1.4.2 anstelle snap7-full-1.4.0 auf meinem raspbian stretch zu installieren.

Morgen wollte ich mal den aufbau von simplyautomationized mit der S7 1200 nachbauen mit seinem Programm und mal schauen ob das 24h läuft.
 
Zuletzt bearbeitet:
Wir der gesamte Pi langsamer?
Ist er gar nicht mehr erreichbar?
Wenn erreichbar -> Was sagt TOP ?
Du startest das Programm nicht zufällig in nem Cron und das immer und immer wieder? :)


Grüße

Marcel
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das gesamte Pi wird langsamer, manchmal erreicht man es noch über putty. Die LED für die Netzwerkverbindung blinkt anfangs erst und wenn das pi nicht mehr erreichbar ist, ist die LED dauerhaft an.
Das Python Programm wir über sudo nano /etc/rc.local gestartet.



https://webnist.de/python-script-auf-dem-raspberry-pi-automatisch-starten/


Habe jetzt mal Gijs Molenaar angeschrieben. Vielleicht erhalte ich eine Antwort
 
Zuletzt bearbeitet:
Hallo
habe eine Antwort von Gijs erhalten. Er mein es liegt an der CPU Temperatur. Ich habe zwar einen Kühlkörper verbaut aber vielleicht ist dieser nicht ausreichend.
Aktuelle CPU Temp

Code:
pi@raspberrypi:~ $ vcgencmd measure_temp
temp=49.9'C
pi@raspberrypi:~ $ vcgencmd measure_volts
volt=1.2000V
pi@raspberrypi:~ $ vcgencmd measure_clock arm
frequency(45)=600000000

Werde es nochmal mit 0,2 sev versuchen und messen.
 
Zuletzt bearbeitet:
Code:
[FONT=Courier New]import os

def getCpuTemperature():
 tempFile = open( "/sys/class/thermal/thermal_zone0/temp" )
 cpu_temp = tempFile.read()
 tempFile.close()
 return float(cpu_temp)/1000
 
print(getCpuTemperature())

[/FONT]

Als Antwort auf deinen "alten" Beitrag ohne Edit

Grüße

Marcel
 
Zurück
Oben