此程序的想法是,把PLC中数据的变化推送到Redis的列表,其他程序,如C#,只需要访问阻塞的列表,省去麻烦的底层访问。
import snap7
import redis
import time
import struct
import json
# PLC连接参数
plc_ip = '127.0.0.1'
plc_rack = 0
plc_slot = 1
db_number = 1
start = 0
length = 20
# 连接到PLC
plc = snap7.client.Client()
plc.connect(plc_ip, plc_rack, plc_slot)
# 连接到Redis
redis_client = redis.StrictRedis(host='127.0.0.1', port=6379, db=0, password='123456')
def convert_to_int16(data):
int16_values = []
for i in range(0, len(data), 2):
# 使用struct解包两个字节
value = struct.unpack('>h', data[i:i+2])[0]
int16_values.append(value)
return int16_values
# 用于存储上一次读取的数据
last_data = convert_to_int16(plc.db_read(db_number, start, length))
redis_key = 'publish_plc_change_data'
try:
while True:
# 读取当前数据
print_time = time.time()
# print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(print_time)))
current_data = convert_to_int16(plc.db_read(db_number, start, length))
# 检查数据是否有变化
if current_data != last_data:
print("数据有变化",current_data)
# 检查每一位是否由0变为1
for i in range(len(current_data)):
if last_data[i]==0 and current_data[i] == 1:
# 数据有变化,写入Redis
# 如果推送整个数组,比如[0,0,0]->[1,1,1]->[1,1,0] 可能会造成多次执行
# 推送序号,还是执行了一次
timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
data_to_push = {
"timestamp": timestamp,
"data": i
}
redis_client.lpush(redis_key, json.dumps(data_to_push))
# 更新上一次读取的数据
last_data = current_data
# 等待1秒钟
time.sleep(1)
finally:
# 断开与PLC的连接
plc.disconnect()