bash
复制代码
# !/usr/bin/env python
# -*- coding:utf-8 -*-
import logging
import os
import struct
import time
from logging.handlers import TimedRotatingFileHandler
import snap7
def setup_logging(log_dir='logs', filename='sub.log', level=logging.INFO, console_level=None):
import sys
os.makedirs(log_dir, exist_ok=True)
log_path = os.path.join(log_dir, filename)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(lineno)d- %(threadName)s - %(message)s')
# 文件按天切分
file_handler = TimedRotatingFileHandler(log_path, when='midnight', interval=1, backupCount=30, encoding='utf-8')
file_handler.setFormatter(formatter)
file_handler.setLevel(level)
root = logging.getLogger()
root.setLevel(level)
logging.getLogger('opcua').setLevel(logging.WARNING)
logging.getLogger('paho').setLevel(logging.WARNING)
logging.getLogger('urllib3').setLevel(logging.WARNING)
# 避免重复添加相同的文件 handler(通过绝对路径判断)
abs_log_path = os.path.abspath(log_path)
if not any(isinstance(h, TimedRotatingFileHandler) and getattr(h, "baseFilename", None) == abs_log_path for h in
root.handlers):
root.addHandler(file_handler)
# 控制台 handler 写到 stdout,确保在 PyCharm 控制台可见
console_level = console_level if console_level is not None else level
existing_console = None
for h in root.handlers:
if isinstance(h, logging.StreamHandler) and getattr(h, "stream", None) in (sys.stdout, sys.stderr):
existing_console = h
break
if existing_console is None:
console = logging.StreamHandler(sys.stdout)
console.setFormatter(formatter)
console.setLevel(console_level)
root.addHandler(console)
else:
# 更新已存在的控制台 handler 的级别与格式
existing_console.setFormatter(formatter)
existing_console.setLevel(console_level)
# 读取DB块中的布尔数组
def read_bool_array_from_db(plc_client, db_number, offset, array_size):
# 计算需要读取的字节数
bytes_to_read = (array_size + 7) // 8
data = plc_client.db_read(db_number, offset, bytes_to_read)
bool_array = []
for i in range(array_size):
byte_index = i // 8
bit_index = i % 8
bool_value = bool(data[byte_index] & (1 << bit_index))
bool_array.append(bool_value)
return bool_array
# 读取DB块中的BYTE数组(8位无符号整数)
def read_byte_array_from_db(plc_client, db_number, offset, array_size):
# 每个BYTE占1个字节
data = plc_client.db_read(db_number, offset, array_size)
byte_array = []
for i in range(array_size):
byte_value = struct.unpack('>B', data[i:i + 1])[0] # 使用'B'表示8位无符号整数
byte_array.append(byte_value)
return byte_array
# 读取DB块中的DINT数组(32位有符号整数)
def read_dint_array_from_db(plc_client, db_number, offset, array_size):
# 每个DINT占4个字节
bytes_to_read = array_size * 4
data = plc_client.db_read(db_number, offset, bytes_to_read)
dint_array = []
for i in range(array_size):
dint_value = struct.unpack('>i', data[i * 4:(i + 1) * 4])[0] # 使用'i'表示32位有符号整数
dint_array.append(dint_value)
return dint_array
# 读取DB块中的UDINT数组(32位无符号整数)
def read_udint_array_from_db(plc_client, db_number, offset, array_size):
# 每个UDINT占4个字节
bytes_to_read = array_size * 4
data = plc_client.db_read(db_number, offset, bytes_to_read)
udint_array = []
for i in range(array_size):
udint_value = struct.unpack('>I', data[i * 4:(i + 1) * 4])[0] # 使用'I'表示32位无符号整数
udint_array.append(udint_value)
return udint_array
# 读取DB块中的INT数组(16位有符号整数,short)
def read_int_array_from_db(plc_client, db_number, offset, array_size):
# 每个INT占2个字节
bytes_to_read = array_size * 2
data = plc_client.db_read(db_number, offset, bytes_to_read)
int_array = []
for i in range(array_size):
int_value = struct.unpack('>h', data[i * 2:(i + 1) * 2])[0] # 使用'h'表示16位有符号整数
int_array.append(int_value)
return int_array
# 读取DB块中的UINT数组(16位无符号整数,short)
def read_uint_array_from_db(plc_client, db_number, offset, array_size):
# 每个UINT占2个字节
bytes_to_read = array_size * 2
data = plc_client.db_read(db_number, offset, bytes_to_read)
uint_array = []
for i in range(array_size):
uint_value = struct.unpack('>H', data[i * 2:(i + 1) * 2])[0] # 使用'H'表示16位无符号整数
uint_array.append(uint_value)
return uint_array
# 读取DB块中的REAL数组(32位浮点数,float)
def read_real_array_from_db(plc_client, db_number, offset, array_size):
# 每个REAL占4个字节
bytes_to_read = array_size * 4
data = plc_client.db_read(db_number, offset, bytes_to_read)
real_array = []
for i in range(array_size):
real_value = struct.unpack('>f', data[i * 4:(i + 1) * 4])[0] # 使用'f'表示32位浮点数
real_array.append(real_value)
return real_array
# 读取DB块中的LONG数组(64位有符号整数)
def read_long_array_from_db(plc_client, db_number, offset, array_size):
# 每个LONG占8个字节
bytes_to_read = array_size * 8
data = plc_client.db_read(db_number, offset, bytes_to_read)
long_array = []
for i in range(array_size):
long_value = struct.unpack('>q', data[i * 8:(i + 1) * 8])[0] # 使用'q'表示64位有符号整数
long_array.append(long_value)
return long_array
# 读取DB块中的ULONG数组(64位无符号整数)
def read_ulong_array_from_db(plc_client, db_number, offset, array_size):
# 每个ULONG占8个字节
bytes_to_read = array_size * 8
data = plc_client.db_read(db_number, offset, bytes_to_read)
ulong_array = []
for i in range(array_size):
ulong_value = struct.unpack('>Q', data[i * 8:(i + 1) * 8])[0] # 使用'Q'表示64位无符号整数
ulong_array.append(ulong_value)
return ulong_array
# 读取DB块中的DOUBLE数组(64位双精度浮点数)
def read_double_array_from_db(plc_client, db_number, offset, array_size):
# 每个DOUBLE占8个字节
bytes_to_read = array_size * 8
data = plc_client.db_read(db_number, offset, bytes_to_read)
double_array = []
for i in range(array_size):
double_value = struct.unpack('>d', data[i * 8:(i + 1) * 8])[0] # 使用'd'表示64位双精度浮点数
double_array.append(double_value)
return double_array
# 读取DB块中的字符串
def read_string_from_db(plc_client, db_number, offset, length):
# 读取指定长度的字节数据
data = plc_client.db_read(db_number, offset, length)
return list(snap7.util.get_string(data, offset))
# 读取DB块中的CHAR数组(字符数组)
def read_char_array_from_db(plc_client, db_number, offset, array_size):
# 每个CHAR占1个字节
data = plc_client.db_read(db_number, offset, array_size)
char_array = []
for i in range(array_size):
char_value = chr(data[i]) # 将字节转换为字符
char_array.append(char_value)
return char_array
if __name__ == "__main__":
setup_logging(log_dir='logs', filename='sub.log')
plc = snap7.client.Client()
# S7连接配置
plc.connect('127.0.0.1', 0, 1, 103) # IP地址, rack, slot, port
print("connected!")
state_opcua = True
print("S7连接成功!")
# opcua_client() # 阻塞线程
# 读取DB1中的数据
db_number = 1
while True:
a = time.time()
# 读取布尔数组(从偏移量0开始,20个布尔值)
bool_array = read_bool_array_from_db(plc, db_number, 0, 20)
# 读取BYTE数组(从偏移量20开始,10个BYTE值)
byte_array = read_byte_array_from_db(plc, db_number, 0, 10)
# 读取有符号DINT整数数组(从偏移量20开始,10个DINT值)
dint_array = read_dint_array_from_db(plc, db_number, 0, 10)
# 读取UDINT数组(从偏移量20开始,10个UDINT值)
udint_array = read_udint_array_from_db(plc, db_number, 0, 10)
# 读取有符号整数数组(从偏移量20开始,10个INT值)
int_array = read_int_array_from_db(plc, db_number, 0, 10)
# 读取无符号整数数组(从偏移量20开始,10个UINT值)
uint_array = read_uint_array_from_db(plc, db_number, 0, 10)
# 读取实数数组(从偏移量10开始,5个REAL值)float
real_array = read_real_array_from_db(plc, db_number, 0, 5)
# 读取长整数数组(从偏移量20开始,10个LONG值)
long_array = read_long_array_from_db(plc, db_number, 0, 10)
# 读取无符号长整数数组(从偏移量20开始,10个ULONG值)
ulong_array = read_ulong_array_from_db(plc, db_number, 0, 10)
# 读取双精度浮点数数组(从偏移量20开始,5个DOUBLE值)
double_array = read_double_array_from_db(plc, db_number, 0, 5)
# 读取字符串(从偏移量20开始,10个字节)
string_value = read_string_from_db(plc, db_number, 0, 10)
# 读取字符数组(从偏移量20开始,10个CHAR值)
char_array = read_char_array_from_db(plc, db_number, 0, 10)
# 输出读取的数据
print(f"布尔数组: {bool_array}")
# print(f"BYTE数组: {byte_array}")
# print(f"DINT数组: {dint_array}")
# print(f"无符号DINT数组: {udint_array}")
# print(f"整数数组short: {int_array}")
# print(f"无符号整数数组short: {uint_array}")
# print(f"实数数组float: {real_array}")
# print(f"长整数数组long: {long_array}")
# print(f"无符号长整数数组long: {ulong_array}")
# print(f"双精度浮点数组double: {double_array}")
# 读取字符串和字符数组有一些符号在里面,要注意,通用都不不适应这两个方法
print(f"字符串: {string_value}")
# print(f"字符数组: {char_array}")
b = time.time()
# print("首次读取耗时:", (b - a) * 1000, "ms")
data = plc.read_area(snap7.types.Areas.DB, 1, 0, 20) # 读取DB1,从偏移量0开始,读取20个字节
plc.db_read(db_number, 0, 20)
# value = snap7.util.get_int(data, 0) # 从数据中获取整数值类型为short
# value = snap7.util.get_bool(data, 0, 0) # 从数据中获取布尔值
# value = snap7.util.get_char(data, 0) # 从数据中获取字符值
value = snap7.util.get_string(data, 0) # 从数据中获取字符串,使用这个方法最好
# print("读取的值:", value)
time.sleep(2)