最近要开发基于TCP/IP协议的西门子S7系列PLC的通讯和数据采集,网上搜罗了一圈发现有python snap7还有HSL这两个工具,不过考虑到商用界限并且鉴于此次开发时间足够,就自己研究上手了,
由于网上解决方案有限,查阅大部分资料只能查到读一些I/O/M之类的接口,DB块基本没有...无赖只好啃manual。
基本上主要用snap7的read_area 、write_area两个方法就可以实现,当然接口众多...我也就没一一去了解,
废话少说~~直接贴代码:
#####################################################################
# equipmenthandler.py
#
# (c) Copyright 2013-2015, Benjamin Parzella. All rights reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#####################################################################
import struct
import snap7
from snap7.util import *
from snap7.snap7exceptions import Snap7Exception
from snap7.snap7types import *
import EAP.LogFile.communication_log_file_handler
db = \
"""DB001 Real 0.0 7.9
DB002 Bool 4.2 1
DB003 Int 6.0 12
DB004 String 8.0 0221190081
DB005 Real 264.0 9.69"""
offsets = {"Bool":2,"Int":2,"Real":4,"DInt":6,"String":256}
class DATAObject(object):
pass
class s7netcommunication:
def __init__(self,ip,port=102,rack=0,slot=0):
self.ip=ip
self.port=port
self.rack=rack
self.slot=slot
self.obj = DATAObject()
self.client = snap7.client.Client()
def Connect(self):
self.client.connect(self.ip, self.rack, self.slot,self.port)
def Disconnect(self):
self.client.disconnect()
def get_data_len(self,bytebit,datatype):
offset_int= []
offset_int.append(int(bytebit.split('.')[0]))
data_len = (max(offset_int))+ int(offsets[datatype])
return data_len
def ReadDBData(self,device_type,data_num,data_len,name,bytebit,datatype):
data=''
if device_type.upper() == 'I':
#data = self.client.read_area(0x81,data_num,0,data_len)
pass
elif device_type.upper() == 'Q':
#data = self.client.read_area(0x82,data_num,0,data_len)
pass
elif device_type.upper() == 'M':
data = self.client.read_area(0x83,data_num,0,data_len)
pass
elif device_type.upper() == 'DB':
data = self.client.read_area(0x84,data_num,0,data_len)
value = None
offset = int(bytebit.split('.')[0])
if datatype=='Real':
value = get_real(data,offset)
if datatype=='Bool':
bit = int(bytebit.split('.')[1])
value = get_bool(data,offset,bit)
if datatype=='Int':
value = get_int(data,offset)
if datatype=='String':
value = get_string(data,offset,256)
self.obj.__setattr__(name,value)
return self.obj
def WriteDBData(self,data_num,data_len,bytebit,datatype,value):
result = self.client.read_area(0x84,data_num,0,data_len)
byte_idx = int(bytebit.split('.')[0])
if datatype=='Bool':
bit_idx = int(bytebit.split('.')[1])
set_bool(result,byte_idx,bit_idx,value)
elif datatype=='Int':
set_int(result,byte_idx,value)
elif datatype=='Real':
set_real(result,byte_idx,value)
elif datatype=='String':
set_string(result,byte_idx,value,256)
self.client.write_area(0x84,data_num,0,result)
S7Net=s7netcommunication('192.168.0.1',102,0,0)
S7Net.Connect()
itemlist = filter(lambda a:a != ' ',db.split('\n'))
space = ' '
items = [{
"name":x.split(space)[0],
"datatype":x.split(space)[1],
"bytebit":x.split(space)[2],
"value":float(x.split(space)[3]) if (x.split(space)[1])=='Real' else (str(x.split(space)[3]) if (x.split(space)[1])=='String' else
(bool(int(x.split(space)[3])) if (x.split(space)[1])=='Bool' else
((int(x.split(space)[3]) if (x.split(space)[1])=='Int' else None))))
}for x in itemlist]
obj = DATAObject()
for x in items:
data_len = S7Net.get_data_len(x['bytebit'] ,x['datatype'])
S7Net.WriteDBData(1,data_len,x['bytebit'],x['datatype'],x['value'])
DATA_obj = S7Net.ReadDBData('DB',1,data_len,x['name'],x['bytebit'] ,x['datatype'])
print(DATA_obj.DB001,DATA_obj.DB002,DATA_obj.DB003,str(DATA_obj.DB004)[0:10],DATA_obj.DB005)