233 lines
8.1 KiB
Python
233 lines
8.1 KiB
Python
|
#!/usr/bin/env python
|
|||
|
# -*- coding: utf-8 -*-
|
|||
|
|
|||
|
"""
|
|||
|
VWED.melsec 模块 - Melsec PLC通信相关功能
|
|||
|
"""
|
|||
|
|
|||
|
from typing import Optional, Union
|
|||
|
from utils.logger import get_logger
|
|||
|
import pymcprotocol
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
class VWEDMelsecModule:
|
|||
|
"""VWED.melsec 模块 - Melsec PLC通信相关功能"""
|
|||
|
|
|||
|
def __init__(self, script_id: str):
|
|||
|
self.script_id = script_id
|
|||
|
self.logger = get_logger(f"script.{script_id}.melsec")
|
|||
|
|
|||
|
def read_boolean(self, ip: str, port: int, address: str) -> Optional[bool]:
|
|||
|
"""Melsec 读取 boolean
|
|||
|
|
|||
|
Args:
|
|||
|
ip (str): 从机 IP
|
|||
|
port (int): 从机端口
|
|||
|
address (str): 读取的地址位
|
|||
|
|
|||
|
Returns:
|
|||
|
Optional[bool]: 读取成功的返回值,失败返回 None
|
|||
|
"""
|
|||
|
|
|||
|
try:
|
|||
|
# 创建Melsec连接
|
|||
|
plc = pymcprotocol.Type3E()
|
|||
|
plc.setaccessopt(commtype="binary")
|
|||
|
plc.connect(ip, port)
|
|||
|
|
|||
|
# 读取布尔值
|
|||
|
result = plc.batchread_bitunits(address, 1)
|
|||
|
plc.close()
|
|||
|
|
|||
|
if result and len(result) > 0:
|
|||
|
value = bool(result[0])
|
|||
|
self.logger.info(f"读取Melsec boolean成功: {ip}:{port} 地址: {address} 值: {value}")
|
|||
|
return value
|
|||
|
else:
|
|||
|
self.logger.warning(f"读取Melsec boolean无数据: {ip}:{port} 地址: {address}")
|
|||
|
return None
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
self.logger.error(f"读取Melsec boolean失败: {ip}:{port} 地址: {address} 错误: {e}")
|
|||
|
return None
|
|||
|
|
|||
|
def read_number(self, ip: str, port: int, address: str) -> Optional[float]:
|
|||
|
"""Melsec 读取 number
|
|||
|
|
|||
|
Args:
|
|||
|
ip (str): 从机 IP
|
|||
|
port (int): 从机端口
|
|||
|
address (str): 读取的地址位
|
|||
|
|
|||
|
Returns:
|
|||
|
Optional[float]: 读取成功的返回值,失败返回 None
|
|||
|
"""
|
|||
|
|
|||
|
try:
|
|||
|
# 创建Melsec连接
|
|||
|
plc = pymcprotocol.Type3E()
|
|||
|
plc.setaccessopt(commtype="binary")
|
|||
|
plc.connect(ip, port)
|
|||
|
|
|||
|
# 读取数值(假设为16位整数)
|
|||
|
result = plc.batchread_wordunits(address, 1)
|
|||
|
plc.close()
|
|||
|
|
|||
|
if result and len(result) > 0:
|
|||
|
value = float(result[0])
|
|||
|
self.logger.info(f"读取Melsec number成功: {ip}:{port} 地址: {address} 值: {value}")
|
|||
|
return value
|
|||
|
else:
|
|||
|
self.logger.warning(f"读取Melsec number无数据: {ip}:{port} 地址: {address}")
|
|||
|
return None
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
self.logger.error(f"读取Melsec number失败: {ip}:{port} 地址: {address} 错误: {e}")
|
|||
|
return None
|
|||
|
|
|||
|
def read_string(self, ip: str, port: int, address: str, length: int) -> Optional[str]:
|
|||
|
"""Melsec 读取 string
|
|||
|
|
|||
|
Args:
|
|||
|
ip (str): 从机 IP
|
|||
|
port (int): 从机端口
|
|||
|
address (str): 读取的地址位
|
|||
|
length (int): 读取的长度
|
|||
|
|
|||
|
Returns:
|
|||
|
Optional[str]: 读取成功的返回值,失败返回 None
|
|||
|
"""
|
|||
|
|
|||
|
try:
|
|||
|
# 创建Melsec连接
|
|||
|
plc = pymcprotocol.Type3E()
|
|||
|
plc.setaccessopt(commtype="binary")
|
|||
|
plc.connect(ip, port)
|
|||
|
|
|||
|
# 读取字符串(每个字符占用2字节)
|
|||
|
word_count = (length + 1) // 2 # 计算需要读取的字数
|
|||
|
result = plc.batchread_wordunits(address, word_count)
|
|||
|
plc.close()
|
|||
|
|
|||
|
if result and len(result) > 0:
|
|||
|
# 将字数据转换为字符串
|
|||
|
byte_data = []
|
|||
|
for word in result:
|
|||
|
byte_data.extend([word & 0xFF, (word >> 8) & 0xFF])
|
|||
|
|
|||
|
# 转换为字符串并去除空字符
|
|||
|
value = bytes(byte_data[:length]).decode('ascii', errors='ignore').rstrip('\x00')
|
|||
|
self.logger.info(f"读取Melsec string成功: {ip}:{port} 地址: {address} 长度: {length} 值: {value}")
|
|||
|
return value
|
|||
|
else:
|
|||
|
self.logger.warning(f"读取Melsec string无数据: {ip}:{port} 地址: {address}")
|
|||
|
return None
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
self.logger.error(f"读取Melsec string失败: {ip}:{port} 地址: {address} 错误: {e}")
|
|||
|
return None
|
|||
|
|
|||
|
def write_boolean(self, ip: str, port: int, address: str, value: bool) -> bool:
|
|||
|
"""Melsec 写入 boolean
|
|||
|
|
|||
|
Args:
|
|||
|
ip (str): 从机 IP
|
|||
|
port (int): 从机端口
|
|||
|
address (str): 写入的地址位
|
|||
|
value (bool): 写入的值
|
|||
|
|
|||
|
Returns:
|
|||
|
bool: 成功返回 True,失败返回 False
|
|||
|
"""
|
|||
|
|
|||
|
try:
|
|||
|
# 创建Melsec连接
|
|||
|
plc = pymcprotocol.Type3E()
|
|||
|
plc.setaccessopt(commtype="binary")
|
|||
|
plc.connect(ip, port)
|
|||
|
|
|||
|
# 写入布尔值
|
|||
|
plc.batchwrite_bitunits(address, [1 if value else 0])
|
|||
|
plc.close()
|
|||
|
|
|||
|
self.logger.info(f"写入Melsec boolean成功: {ip}:{port} 地址: {address} 值: {value}")
|
|||
|
return True
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
self.logger.error(f"写入Melsec boolean失败: {ip}:{port} 地址: {address} 值: {value} 错误: {e}")
|
|||
|
return False
|
|||
|
|
|||
|
def write_number(self, ip: str, port: int, address: str, value: float) -> bool:
|
|||
|
"""Melsec 写入 number
|
|||
|
|
|||
|
Args:
|
|||
|
ip (str): 从机 IP
|
|||
|
port (int): 从机端口
|
|||
|
address (str): 写入的地址位
|
|||
|
value (float): 写入的值
|
|||
|
|
|||
|
Returns:
|
|||
|
bool: 成功返回 True,失败返回 False
|
|||
|
"""
|
|||
|
|
|||
|
try:
|
|||
|
# 创建Melsec连接
|
|||
|
plc = pymcprotocol.Type3E()
|
|||
|
plc.setaccessopt(commtype="binary")
|
|||
|
plc.connect(ip, port)
|
|||
|
|
|||
|
# 写入数值(转换为整数)
|
|||
|
int_value = int(value)
|
|||
|
plc.batchwrite_wordunits(address, [int_value])
|
|||
|
plc.close()
|
|||
|
|
|||
|
self.logger.info(f"写入Melsec number成功: {ip}:{port} 地址: {address} 值: {value}")
|
|||
|
return True
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
self.logger.error(f"写入Melsec number失败: {ip}:{port} 地址: {address} 值: {value} 错误: {e}")
|
|||
|
return False
|
|||
|
|
|||
|
def write_string(self, ip: str, port: int, address: str, value: str) -> bool:
|
|||
|
"""Melsec 写入 string
|
|||
|
|
|||
|
Args:
|
|||
|
ip (str): 从机 IP
|
|||
|
port (int): 从机端口
|
|||
|
address (str): 写入的地址位
|
|||
|
value (str): 写入的值
|
|||
|
|
|||
|
Returns:
|
|||
|
bool: 成功返回 True,失败返回 False
|
|||
|
"""
|
|||
|
|
|||
|
try:
|
|||
|
# 创建Melsec连接
|
|||
|
plc = pymcprotocol.Type3E()
|
|||
|
plc.setaccessopt(commtype="binary")
|
|||
|
plc.connect(ip, port)
|
|||
|
|
|||
|
# 准备字符串数据
|
|||
|
byte_data = value.encode('ascii')[:254] # 限制长度并编码为ASCII
|
|||
|
# 补齐到偶数长度
|
|||
|
if len(byte_data) % 2 == 1:
|
|||
|
byte_data += b'\x00'
|
|||
|
|
|||
|
# 转换为字数据
|
|||
|
word_data = []
|
|||
|
for i in range(0, len(byte_data), 2):
|
|||
|
word = byte_data[i] | (byte_data[i+1] << 8)
|
|||
|
word_data.append(word)
|
|||
|
|
|||
|
# 写入字符串
|
|||
|
plc.batchwrite_wordunits(address, word_data)
|
|||
|
plc.close()
|
|||
|
|
|||
|
self.logger.info(f"写入Melsec string成功: {ip}:{port} 地址: {address} 值: {value}")
|
|||
|
return True
|
|||
|
|
|||
|
except Exception as e:
|
|||
|
self.logger.error(f"写入Melsec string失败: {ip}:{port} 地址: {address} 值: {value} 错误: {e}")
|
|||
|
return False
|