735 lines
27 KiB
Python
735 lines
27 KiB
Python
"""
|
||
S7 PLC通信模块
|
||
"""
|
||
|
||
import logging
|
||
import snap7
|
||
from snap7.type import *
|
||
from snap7.util import *
|
||
from typing import Optional, Any
|
||
from datetime import datetime
|
||
|
||
# 配置日志
|
||
logging.basicConfig(level=logging.INFO,
|
||
format='%(asctime)s - %(name)s - %(funcName)s - %(levelname)s - %(message)s')
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class VWEDS7Module:
|
||
"""
|
||
S7 PLC通信模块类
|
||
"""
|
||
|
||
def __init__(self, script_id: str):
|
||
self.script_id = script_id
|
||
logger.debug(f"初始化 S7 模块,脚本ID: {script_id}")
|
||
|
||
def _get_rack_slot(self, plc_type: str) -> tuple:
|
||
"""
|
||
根据PLC类型获取默认的rack和slot值
|
||
|
||
Args:
|
||
plc_type (str): PLC类型
|
||
|
||
Returns:
|
||
tuple: (rack, slot) 默认值
|
||
"""
|
||
# 根据常见默认值设置
|
||
# S7-200 SMART: rack=0, slot=1
|
||
# S7-300: rack=0, slot=2
|
||
# S7-400: rack=0, slot=3
|
||
# S7-1200: rack=0, slot=1
|
||
# S7-1500: rack=0, slot=1
|
||
# S7-200: rack=0, slot=1
|
||
|
||
defaults = {
|
||
'S200Smart': (0, 1),
|
||
'S300': (0, 2),
|
||
'S400': (0, 3),
|
||
'S1200': (0, 1),
|
||
'S1500': (0, 1),
|
||
'S200': (0, 1)
|
||
}
|
||
|
||
return defaults.get(plc_type, (0, 1))
|
||
|
||
def _parse_address(self, block_and_offset: str) -> tuple:
|
||
"""
|
||
解析地址字符串,返回区域、DB号、字节地址和位地址
|
||
|
||
Args:
|
||
block_and_offset (str): 地址字符串,如M100, DB1.100, DB1.100.7等
|
||
|
||
Returns:
|
||
tuple: (area, db_number, byte_addr, bit_addr)
|
||
"""
|
||
area = None
|
||
db_number = 0
|
||
byte_addr = 0
|
||
bit_addr = None
|
||
|
||
# 移除空格
|
||
block_and_offset = block_and_offset.replace(' ', '')
|
||
|
||
# 处理DB块地址
|
||
if block_and_offset.startswith('DB'):
|
||
parts = block_and_offset[2:].split('.')
|
||
if len(parts) >= 2:
|
||
db_number = int(parts[0])
|
||
byte_addr = int(parts[1])
|
||
if len(parts) == 3:
|
||
bit_addr = int(parts[2])
|
||
area = Areas.DB
|
||
# 处理其他区域地址
|
||
else:
|
||
if block_and_offset[0] == 'M':
|
||
area = Areas.MK
|
||
addr_part = block_and_offset[1:]
|
||
elif block_and_offset[0] == 'I':
|
||
area = Areas.PE
|
||
addr_part = block_and_offset[1:]
|
||
elif block_and_offset[0] == 'Q':
|
||
area = Areas.PA
|
||
addr_part = block_and_offset[1:]
|
||
elif block_and_offset[0] == 'V':
|
||
# V区通常映射到M区
|
||
area = Areas.MK
|
||
addr_part = block_and_offset[1:]
|
||
elif block_and_offset[0] == 'T':
|
||
area = Areas.TM
|
||
addr_part = block_and_offset[1:]
|
||
elif block_and_offset[0] == 'C':
|
||
area = Areas.CT
|
||
addr_part = block_and_offset[1:]
|
||
elif block_and_offset[0] == 'AI':
|
||
area = Areas.AI
|
||
addr_part = block_and_offset[2:]
|
||
elif block_and_offset[0] == 'AQ':
|
||
area = Areas.AQ
|
||
addr_part = block_and_offset[2:]
|
||
else:
|
||
raise ValueError(f"不支持的地址区域: {block_and_offset[0]}")
|
||
|
||
# 处理地址中的位信息
|
||
if '.' in addr_part:
|
||
parts = addr_part.split('.')
|
||
byte_addr = int(parts[0])
|
||
bit_addr = int(parts[1])
|
||
else:
|
||
byte_addr = int(addr_part)
|
||
|
||
return area, db_number, byte_addr, bit_addr
|
||
|
||
def read_s7_int(self, plc_type: str, ip: str, block_and_offset: str) -> Optional[int]:
|
||
"""
|
||
S7 读取 Int。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 读取的地址,如M100, DB1.100等
|
||
|
||
Returns:
|
||
Optional[int]: 读取到的整数值,失败则返回None
|
||
"""
|
||
try:
|
||
# 获取rack和slot
|
||
rack, slot = self._get_rack_slot(plc_type)
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 读取数据
|
||
if area == Areas.DB:
|
||
data = client.db_read(db_number, byte_addr, 2) # Int是2个字节
|
||
else:
|
||
data = client.read_area(area, 0, byte_addr, 2)
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
# 解析数据
|
||
value = snap7.util.get_int(data, 0)
|
||
logger.info(f"成功读取 {plc_type} {ip} 的 {block_and_offset} 地址的Int值: {value}")
|
||
return value
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - read_s7_int - 读取Int值时发生错误: {e}")
|
||
return None
|
||
|
||
def read_s7_dint(self, plc_type: str, ip: str, block_and_offset: str) -> Optional[int]:
|
||
"""
|
||
S7 读取 DInt。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 读取的地址,如M100, DB1.100等
|
||
|
||
Returns:
|
||
Optional[int]: 读取到的双整数值,失败则返回None
|
||
"""
|
||
try:
|
||
# 获取rack和slot
|
||
rack, slot = self._get_rack_slot(plc_type)
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 读取数据
|
||
if area == Areas.DB:
|
||
data = client.db_read(db_number, byte_addr, 4) # DInt是4个字节
|
||
else:
|
||
data = client.read_area(area, 0, byte_addr, 4)
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
# 解析数据
|
||
value = snap7.util.get_dint(data, 0)
|
||
logger.info(f"成功读取 {plc_type} {ip} 的 {block_and_offset} 地址的DInt值: {value}")
|
||
return value
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - read_s7_dint - 读取DInt值时发生错误: {e}")
|
||
return None
|
||
|
||
def read_s7_word(self, plc_type: str, ip: str, block_and_offset: str) -> Optional[int]:
|
||
"""
|
||
S7 读取 Word。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 读取的地址,如M100, DB1.100等
|
||
|
||
Returns:
|
||
Optional[int]: 读取到的字值,失败则返回None
|
||
"""
|
||
try:
|
||
# 获取rack和slot
|
||
rack, slot = self._get_rack_slot(plc_type)
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 读取数据
|
||
if area == Areas.DB:
|
||
data = client.db_read(db_number, byte_addr, 2) # Word是2个字节
|
||
else:
|
||
data = client.read_area(area, 0, byte_addr, 2)
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
# 解析数据
|
||
value = snap7.util.get_word(data, 0)
|
||
logger.info(f"成功读取 {plc_type} {ip} 的 {block_and_offset} 地址的Word值: {value}")
|
||
return value
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - read_s7_word - 读取Word值时发生错误: {e}")
|
||
return None
|
||
|
||
def read_s7_dword(self, plc_type: str, ip: str, block_and_offset: str) -> Optional[int]:
|
||
"""
|
||
S7 读取 DWord。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 读取的地址,如M100, DB1.100等
|
||
|
||
Returns:
|
||
Optional[int]: 读取到的双字值,失败则返回None
|
||
"""
|
||
try:
|
||
# 获取rack和slot
|
||
rack, slot = self._get_rack_slot(plc_type)
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 读取数据
|
||
if area == Areas.DB:
|
||
data = client.db_read(db_number, byte_addr, 4) # DWord是4个字节
|
||
else:
|
||
data = client.read_area(area, 0, byte_addr, 4)
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
# 解析数据
|
||
value = snap7.util.get_dword(data, 0)
|
||
logger.info(f"成功读取 {plc_type} {ip} 的 {block_and_offset} 地址的DWord值: {value}")
|
||
return value
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - read_s7_dword - 读取DWord值时发生错误: {e}")
|
||
return None
|
||
|
||
def read_s7_string(self, plc_type: str, ip: str, block_and_offset: str) -> Optional[str]:
|
||
"""
|
||
S7 读取 String。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 读取的地址,如M100, DB1.100等
|
||
|
||
Returns:
|
||
Optional[str]: 读取到的字符串值,失败则返回None
|
||
"""
|
||
try:
|
||
# 获取rack和slot
|
||
rack, slot = self._get_rack_slot(plc_type)
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 先读取字符串的长度信息(前2个字节)
|
||
# 第一个字节是最大长度,第二个字节是实际长度
|
||
if area == Areas.DB:
|
||
length_data = client.db_read(db_number, byte_addr, 2)
|
||
else:
|
||
length_data = client.read_area(area, 0, byte_addr, 2)
|
||
|
||
# 获取字符串的实际长度
|
||
max_length = length_data[0] # 最大长度
|
||
actual_length = length_data[1] # 实际长度
|
||
|
||
# 读取字符串数据(根据实际长度读取)
|
||
if area == Areas.DB:
|
||
data = client.db_read(db_number, byte_addr + 2, actual_length)
|
||
else:
|
||
data = client.read_area(area, 0, byte_addr + 2, actual_length)
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
# 解析数据
|
||
value = data.decode('utf-8').rstrip('\x00').rstrip() # 移除可能的空字符和空格
|
||
logger.info(f"成功读取 {plc_type} {ip} 的 {block_and_offset} 地址的String值: {value}")
|
||
return value
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - read_s7_string - 读取String值时发生错误: {e}")
|
||
return None
|
||
|
||
def read_s7_boolean(self, plc_type: str, ip: str, block_and_offset: str) -> Optional[bool]:
|
||
"""
|
||
S7 读取 Bool。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 读取的地址,如M100.0, DB1.100.7等
|
||
|
||
Returns:
|
||
Optional[bool]: 读取到的布尔值,失败则返回None
|
||
"""
|
||
try:
|
||
# 获取rack和slot
|
||
rack, slot = self._get_rack_slot(plc_type)
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 检查是否有位地址
|
||
if bit_addr is None:
|
||
raise ValueError("读取布尔值需要指定位地址,如M100.0")
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 读取数据
|
||
if area == Areas.DB:
|
||
data = client.db_read(db_number, byte_addr, 1) # 读取1个字节
|
||
else:
|
||
data = client.read_area(area, 0, byte_addr, 1)
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
# 解析数据
|
||
value = snap7.util.get_bool(data, 0, bit_addr)
|
||
logger.info(f"成功读取 {plc_type} {ip} 的 {block_and_offset} 地址的Boolean值: {value}")
|
||
return value
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - read_s7_boolean - 读取Boolean值时发生错误: {e}")
|
||
return None
|
||
|
||
def write_s7_int(self, plc_type: str, ip: str, block_and_offset: str, value: int) -> bool:
|
||
"""
|
||
S7 写入 Int。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 写入的地址,如M100, DB1.100等
|
||
value (int): 要写入的整数值
|
||
|
||
Returns:
|
||
bool: 写入成功返回True,失败返回False
|
||
"""
|
||
try:
|
||
# 获取rack和slot
|
||
rack, slot = self._get_rack_slot(plc_type)
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 准备数据
|
||
data = bytearray(2)
|
||
snap7.util.set_word(data, 0, value)
|
||
|
||
# 写入数据
|
||
logger.info(f"准备写入数据到DB{db_number}, 偏移量{byte_addr}, 数据: {data}")
|
||
if area == Areas.DB:
|
||
client.db_write(db_number, byte_addr, data)
|
||
else:
|
||
client.write_area(area, 0, byte_addr, data)
|
||
logger.info(f"数据写入完成")
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
logger.info(f"成功向 {plc_type} {ip} 的 {block_and_offset} 地址写入Int值 {value}")
|
||
return True
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - write_s7_int - 写入Int值时发生错误: {e}")
|
||
return False
|
||
|
||
def write_s7_dint(self, plc_type: str, ip: str, block_and_offset: str, value: int) -> bool:
|
||
"""
|
||
S7 写入 DInt。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 写入的地址,如M100, DB1.100等
|
||
value (int): 要写入的双整数值
|
||
|
||
Returns:
|
||
bool: 写入成功返回True,失败返回False
|
||
"""
|
||
try:
|
||
# 获取rack和slot
|
||
rack, slot = self._get_rack_slot(plc_type)
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 准备数据
|
||
data = bytearray(4)
|
||
snap7.util.set_dint(data, 0, value)
|
||
|
||
# 写入数据
|
||
if area == Areas.DB:
|
||
client.db_write(db_number, byte_addr, data)
|
||
else:
|
||
client.write_area(area, 0, byte_addr, data)
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
logger.info(f"成功向 {plc_type} {ip} 的 {block_and_offset} 地址写入DInt值 {value}")
|
||
return True
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - write_s7_dint - 写入DInt值时发生错误: {e}")
|
||
return False
|
||
|
||
def write_s7_word(self, plc_type: str, ip: str, block_and_offset: str, value: int) -> bool:
|
||
"""
|
||
S7 写入 Word。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 写入的地址,如M100, DB1.100等
|
||
value (int): 要写入的字值
|
||
|
||
Returns:
|
||
bool: 写入成功返回True,失败返回False
|
||
"""
|
||
try:
|
||
# 获取rack和slot
|
||
rack, slot = self._get_rack_slot(plc_type)
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 准备数据
|
||
data = bytearray(2)
|
||
snap7.util.set_word(data, 0, value)
|
||
|
||
# 写入数据
|
||
if area == Areas.DB:
|
||
client.db_write(db_number, byte_addr, data)
|
||
else:
|
||
client.write_area(area, 0, byte_addr, data)
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
logger.info(f"成功向 {plc_type} {ip} 的 {block_and_offset} 地址写入Word值 {value}")
|
||
return True
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - write_s7_word - 写入Word值时发生错误: {e}")
|
||
return False
|
||
|
||
def write_s7_dword(self, plc_type: str, ip: str, block_and_offset: str, value: int) -> bool:
|
||
"""
|
||
S7 写入 DWord。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 写入的地址,如M100, DB1.100等
|
||
value (int): 要写入的双字值
|
||
|
||
Returns:
|
||
bool: 写入成功返回True,失败返回False
|
||
"""
|
||
try:
|
||
# 获取rack和slot
|
||
rack, slot = self._get_rack_slot(plc_type)
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 准备数据
|
||
data = bytearray(4)
|
||
snap7.util.set_dword(data, 0, value)
|
||
|
||
# 写入数据
|
||
if area == Areas.DB:
|
||
client.db_write(db_number, byte_addr, data)
|
||
else:
|
||
client.write_area(area, 0, byte_addr, data)
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
logger.info(f"成功向 {plc_type} {ip} 的 {block_and_offset} 地址写入DWord值 {value}")
|
||
return True
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - write_s7_dword - 写入DWord值时发生错误: {e}")
|
||
return False
|
||
|
||
def write_s7_string(self, plc_type: str, ip: str, block_and_offset: str, value: str) -> bool:
|
||
"""
|
||
S7 写入 String。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 写入的地址,如M100, DB1.100等
|
||
value (str): 要写入的字符串值
|
||
|
||
Returns:
|
||
bool: 写入成功返回True,失败返回False
|
||
"""
|
||
try:
|
||
# 获取rack和slot
|
||
rack, slot = self._get_rack_slot(plc_type)
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 准备数据
|
||
# 字符串格式:前2个字节为长度,后面是字符串内容
|
||
data = bytearray(256) # 最大256字节
|
||
encoded_value = value.encode('utf-8')
|
||
length = min(len(encoded_value), 254) # 最大长度254
|
||
snap7.util.set_word(data, 0, length) # 设置长度
|
||
data[2:2+length] = encoded_value[:length] # 设置字符串内容
|
||
|
||
# 写入数据
|
||
if area == Areas.DB:
|
||
client.db_write(db_number, byte_addr, data)
|
||
else:
|
||
client.write_area(area, 0, byte_addr, data)
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
logger.info(f"成功向 {plc_type} {ip} 的 {block_and_offset} 地址写入String值 {value}")
|
||
return True
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - write_s7_string - 写入String值时发生错误: {e}")
|
||
return False
|
||
|
||
def write_s7_boolean(self, plc_type: str, ip: str, block_and_offset: str, value: bool) -> bool:
|
||
"""
|
||
S7 写入 Bool。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 写入的地址,如M100.0, DB1.100.7等
|
||
value (bool): 要写入的布尔值
|
||
|
||
Returns:
|
||
bool: 写入成功返回True,失败返回False
|
||
"""
|
||
try:
|
||
# 获取rack和slot
|
||
rack, slot = self._get_rack_slot(plc_type)
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 检查是否有位地址
|
||
if bit_addr is None:
|
||
raise ValueError("写入布尔值需要指定位地址,如M100.0")
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 读取当前字节数据
|
||
if area == Areas.DB:
|
||
data = client.db_read(db_number, byte_addr, 1)
|
||
else:
|
||
data = client.read_area(area, 0, byte_addr, 1)
|
||
|
||
# 设置布尔值
|
||
snap7.util.set_bool(data, 0, bit_addr, value)
|
||
|
||
# 写入数据
|
||
if area == Areas.DB:
|
||
client.db_write(db_number, byte_addr, data)
|
||
else:
|
||
client.write_area(area, 0, byte_addr, data)
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
logger.info(f"成功向 {plc_type} {ip} 的 {block_and_offset} 地址写入Boolean值 {value}")
|
||
return True
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - write_s7_boolean - 写入Boolean值时发生错误: {e}")
|
||
return False
|
||
|
||
def write_s7(self, plc_type: str, ip: str, block_and_offset: str, value: bytes, rack: int = 0, slot: int = 1) -> bool:
|
||
"""
|
||
S7 通用写入。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 写入的地址,如M100, DB1.100等
|
||
value (bytes): 要写入的字节数据
|
||
rack (int): 中央机架,默认为0
|
||
slot (int): CPU模块插槽号,默认为1
|
||
|
||
Returns:
|
||
bool: 写入成功返回True,失败返回False
|
||
"""
|
||
try:
|
||
# 获取rack和slot的默认值
|
||
default_rack, default_slot = self._get_rack_slot(plc_type)
|
||
if rack == 0 and slot == 1:
|
||
rack, slot = default_rack, default_slot
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 写入数据
|
||
if area == Areas.DB:
|
||
client.db_write(db_number, byte_addr, value)
|
||
else:
|
||
client.write_area(area, 0, byte_addr, value)
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
logger.info(f"成功向 {plc_type} {ip} 的 {block_and_offset} 地址写入数据 {value}")
|
||
return True
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - write_s7 - 通用写入时发生错误: {e}")
|
||
return False
|
||
|
||
def read_s7(self, plc_type: str, ip: str, block_and_offset: str, size: int, rack: int = 0, slot: int = 1) -> Optional[bytes]:
|
||
"""
|
||
S7 通用读取。
|
||
|
||
Args:
|
||
plc_type (str): PLC 类型,可选值:S1200/S300/S400/S1500/S200Smart/S200
|
||
ip (str): PLC IP地址
|
||
block_and_offset (str): 读取的地址,如M100, DB1.100等
|
||
size (int): 读取的数据大小(字节数)
|
||
rack (int): 中央机架,默认为0
|
||
slot (int): CPU模块插槽号,默认为1
|
||
|
||
Returns:
|
||
Optional[bytes]: 读取到的字节数据,失败则返回None
|
||
"""
|
||
try:
|
||
# 获取rack和slot的默认值
|
||
default_rack, default_slot = self._get_rack_slot(plc_type)
|
||
if rack == 0 and slot == 1:
|
||
rack, slot = default_rack, default_slot
|
||
|
||
# 解析地址
|
||
area, db_number, byte_addr, bit_addr = self._parse_address(block_and_offset)
|
||
|
||
# 创建客户端并连接
|
||
client = snap7.client.Client()
|
||
client.connect(ip, rack, slot, 1102)
|
||
|
||
# 读取数据
|
||
if area == Areas.DB:
|
||
data = client.db_read(db_number, byte_addr, size)
|
||
else:
|
||
data = client.read_area(area, 0, byte_addr, size)
|
||
|
||
# 断开连接
|
||
client.disconnect()
|
||
|
||
logger.info(f"成功读取 {plc_type} {ip} 的 {block_and_offset} 地址的 {size} 字节数据")
|
||
return data
|
||
except Exception as e:
|
||
logger.error(f"{datetime.now()} - VWEDS7Module - read_s7 - 通用读取时发生错误: {e}")
|
||
return None |