Pages

Sunday, March 15, 2015

Raspberry Pi SCADA Part 3: Communicate with the Pi using S7 Protocol.





I've been planning on trying this and have been able to get some success. In this example we are going to serve up temperature from the Raspberry Pi using Siemens S7 Protocol. I'm using Wonderware and their DAServer in my tests and will show images of the setup. 

For this example in Modbus TCP see here
To use the Pi to communicate with a PLC see here


First From a fresh Raspbian Image:

For Raspberry Pi 2 B add the following to the bottom boot/config.txt

#device tree config
dtoverlay=w1-gpio,gpiopin=4


Add the following to the /etc/modules

w1-gpio
w1-therm

Install python pip:

sudo apt-get install python-pip
#Download and build the latest snap7 library:

wget http://iweb.dl.sourceforge.net/project/snap7/1.3.0/snap7-full-1.3.0.tar.gz
tar -zxvf snap7-full-1.3.0.tar.gz
cd snap7-full-1.2.1/build/unix
#if you have a Raspberry Pi 2 B use this command to compile:
make –f arm_v7_linux.mk
sudo cp ../bin/arm_v7-linux/libsnap7.so /usr/lib/
sudo ldconfig

#if you have a Raspberry B,B+,A,A+ then use this command to compile:
make –f arm_v6_linux.mk all
sudo cp ../bin/arm_v6-linux/libsnap7.so /usr/lib/
sudo ldconfig

Download and install python-snap7

sudo pip install python-snap7

Now the Pi should be ready!

We are going to serve up temperature data from a DS18b20 probe connected to the pi. If you are unsure how to connected the probe see here
import time,ctypes
from ctypes import *
import logging
from threading import Thread
import snap7
import snap7.snap7types
import sys
import os
from time import sleep

logging.basicConfig()
logger = logging.getLogger()
logger.setLevel(logging.INFO)
globalData = (snap7.snap7types.wordlen_to_ctypes[snap7.snap7types.S7WLByte]*128)()
digitalOutputs = (snap7.snap7types.wordlen_to_ctypes[snap7.snap7types.S7WLByte]*16)()
digitalInputs = (snap7.snap7types.wordlen_to_ctypes[snap7.snap7types.S7WLByte]*128)()
server = None

class TempProbe(Thread):
    """
     A class for getting the current temp of a DS18B20
    """
    def __init__(self, fileName='',tempChangeEvent=None):
        Thread.__init__(self)
        self.tempDir = '/sys/bus/w1/devices/'
        list = os.listdir(self.tempDir)
        if(list[0][:2]=="28"):
         fileName=list[0]
        self.fileName = fileName
        self.currentTemp = -999
        self.correctionFactor = 1
        self.enabled = True
        self.oldTemp = 0
        self.temperatureChangeEvent=tempChangeEvent
    def run(self):
            while self.enabled:
                try:
                        f = open(self.tempDir + self.fileName + "/w1_slave", 'r')
                        lines = f.readlines()
                        crcLine = lines[0]
                        tempLine = lines[1]
                        result_list = tempLine.split("=")
                        temp = float(result_list[-1])/1000      # temp in Celsius
                        temp += self.correctionFactor           # correction factor
                # if you want to convert to Celsius, comment this line
                        temp = (9.0/5.0)*temp + 32
                        if crcLine.find("NO") > -1:
                                temp = -999
                        self.currentTemp = temp
                        if self.currentTemp != self.oldTemp and self.temperatureChangeEvent:
                                self.oldTemp = self.currentTemp
                                self.temperatureChangeEvent(self.currentTemp)

                except IOError as e:
                        print "Error: File " + self.tempDir + self.fileName + "/w1_slave" + " does not exist"
                        sleep(5)
                        pass
                sleep(1)

    # returns the current temp for the probe
    def getCurrentTemp(self):
        return self.currentTemp

    def setEnabled(self, enabled):
        self.enabled = enabled

    def isEnabled(self):
        return self.enabled

temp_probe=None

def mainloop():
        server = snap7.server.Server()
        global globaldata
        server.register_area(snap7.snap7types.srvAreaPA, 0, digitalOutputs)     # digital outputs
        server.register_area(snap7.snap7types.srvAreaMK, 0, globalData)         # internal memory
        server.register_area(snap7.snap7types.srvAreaPE, 0, digitalInputs)      # digital inputs
        server.start()
        global temp_probe
        temp_probe = TempProbe()
        temp_probe.start()       # start getting temperature async
        while True:
                while True:
                        event = server.pick_event()
                        # write temperature to input memory Input Real 67 (IREAL67)
                        snap7.util.set_real(digitalInputs, 67, temp_probe.getCurrentTemp())

                        # fires the following when an event happens (connecting clients, read requests...)
                        if event:
                                #logger.info(server.event_text(event))
                                # print server.event_text(event)
                                print temp_probe.getCurrentTemp()

                        else:
                                break
                time.sleep(.01)
        server.stop()
        server.destroy()
        temp_probe.setEnabled(False)
        temp_probe.join()

if __name__ == '__main__':
    if len(sys.argv) > 1:
        snap7.common.load_library(sys.argv[1])
    mainloop()
    temp_probe.setEnabled(False)
    temp_probe.join()

Now run it!

Setting up your Wonderware and DAserver

Add a S7Cp device
Put in the Ip Address of your Raspberry pi


Create a device group.  I called mine Pi

Add your device items. In this example we are doing temperature at IREAL67

Create an Access  Name in your wonderware. I called mine Pi

Create a tagname and reference it to our Temperature item

attach your tagname to a text field



If you wish me to show anymore examples of how to write or read inputs or outputs in the pi using this protocol please let me know.