Saturday, December 13, 2014

Raspberry Pi getting data from a S7-1200 PLC


UPDATE: If you want the raspberry pi to be the s7 server go here
UPDATE 2: If you want to see communication with S7-200 go here
UPDATE 3: Video walkthrough on setup go here

I recently borrowed a S7-1200 PLC from work to see if I could get data from it using a Raspberry Pi. In my search for something I found that Snap7 was the best option.
Steps to getting it work
  1. Download and compile snap7 (http://sourceforge.net/projects/snap7/files/1.2.1/snap7-full-1.2.1.tar.gz/download)
  2. Download and install python library to use snap7 (https://pypi.python.org/pypi/python-snap7)


#download and compile snap7 for rpi

wget http://sourceforge.net/projects/snap7/files/1.2.1/snap7-full-1.2.1.tar.gz/download 
tar -zxvf snap7-full-1.2.1.tar.gz
cd snap7-full-1.2.1/build/unix
sudo make –f arm_v6_linux.mk all

#copy compiled library to your lib directories
sudo cp ../bin/arm_v6-linux/libsnap7.so /usr/lib/libsnap7.so
sudo cp ../bin/arm_v6-linux/libsnap7.so /usr/local/lib/libsnap7.so

#install python pip if you don't have it:
sudo apt-get install python-pip
sudo pip install python-snap7

You will need to edit the lib_location on common.py in the /usr/local/lib/python2.7/dist-packages/snap7/ directory
Add a line in the __init__ part of the Snap7Library class:
lib_location='/usr/local/lib/libsnap7.so' 
example below:


class Snap7Library(object):
    """
    Snap7 loader and encapsulator. We make this a singleton to make
    sure the library is loaded only once.
    """
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = object.__new__(cls)
            cls._instance.lib_location = None
            cls._instance.cdll = None
        return cls._instance

    def __init__(self, lib_location=None):
        lib_location='/usr/local/lib/libsnap7.so' # add this line here
        if self.cdll:
            return
        self.lib_location = lib_location or self.lib_location or find_library('snap7')
        if not self.lib_location:
            msg = "can't find snap7 library. If installed, try running ldconfig"
            raise Snap7Exception(msg)
        self.cdll = cdll.LoadLibrary(self.lib_location)

Now you can write your client code :-)
Here's an example on how to connect and read an output Q0.0:
from time import sleep
import snap7
from snap7.util import *
import struct

plc = snap7.client.Client()
plc.connect("192.168.12.73",0,1)

area = 0x82    # area for Q memory
start = 0      # location we are going to start the read
length = 1     # length in bytes of the read
bit = 0        # which bit in the Q memory byte we are reading

byte = plc.read_area(area,0,start,length)
print "Q0.0:",get_bool(mbyte,0,bit)
plc.disconnect()



I created a helper class on my github here to make the syntax easier for people who are used to DAServer and Ladder:
https://github.com/SimplyAutomationized/raspberrypi/raw/master/S7-1200pi/S71200.py
Example on how to use it:
import S71200
from time import sleep
import snap7
from snap7.util import *
import struct

plc = S71200.S71200("192.168.21.65")
plc.writeMem('QX0.0',True) # write Q0.0 to be true, which will only turn on the output if it isn't connected to any rung in your ladder code
print plc.getMem('MX0.1') # read memory bit M0.1
print plc.getMem('IX0.0') # read input bit I0.0
print plc.getMem("FREAL100") # read real from MD100
print plc.getMem("MW20") # read int word from MW20
print plc.getMem("MB24",254) # write to MB24 the value 254
plc.plc.disconnect()



Let me know if there are questions. Hope I can help :-)
Also let me know if you can help me clean up my S71200.py helper class. I know it looks messy.

Follow me to get updates on a Raspberry pi Sensor the DA or OPC server can get data using S7 protocol.
+Simply Automationized
Check out my other SCADA posts