Python读取三菱PLC数据

HslCommunication模块

参考文章

python 读写三菱PLC数据,使用以太网读写Q系列,L系列,Fx系列的PLC数据

协议

MC协议

安装

pip install HslCommunication

常用类

Qna3E协议的二进制类 MelsecMcNet
Qna3E协议的ascii类 MelsecMcAsciiNet
A兼容1E协议的二进制类 MelsecA1ENet

测试示例
from HslCommunication import MelsecMcNet
from HslCommunication import SoftBasic
 
def printReadResult(result):
    if result.IsSuccess:
        print(result.Content)
    else:
        print("failed   "+result.Message)
def printWriteResult(result):
    if result.IsSuccess:
        print("success")
    else:
        print("falied  " + result.Message)
 
if __name__ == "__main__":
    print(SoftBasic.GetUniqueStringByGuidAndRandom())
    melsecNet = MelsecMcNet("192.168.8.12",6002)
    if melsecNet.ConnectServer().IsSuccess == False:
        print("connect falied  ")
    else:
        # bool read write test
        melsecNet.WriteBool("M200",True)
        printReadResult(melsecNet.ReadBool("M200"))
 
        # bool array read write test
        melsecNet.WriteBool("M300",[True,False,True,True,False])
        printReadResult(melsecNet.ReadBool("M300",5))
 
        # int16 read write test
        melsecNet.WriteInt16("D200", 12358)
        printReadResult(melsecNet.ReadInt16("D200"))
 
        # int16 read write test
        melsecNet.WriteInt16("D201", -12358)
        printReadResult(melsecNet.ReadInt16("D201"))
 
        # uint16 read write test
        melsecNet.WriteUInt16("D202", 52358)
        printReadResult(melsecNet.ReadUInt16("D202"))
 
        # int32 read write test
        melsecNet.WriteInt32("D210", 12345678)
        printReadResult(melsecNet.ReadInt32("D210"))
 
        # int32 read write test
        melsecNet.WriteInt32("D212", -12345678)
        printReadResult(melsecNet.ReadInt32("D212"))
 
        # uint32 read write test
        melsecNet.WriteUInt32("D214", 123456789)
        printReadResult(melsecNet.ReadInt32("D214"))
 
        # int64 read write test
        melsecNet.WriteInt64("D220", 12345678901234)
        printReadResult(melsecNet.ReadInt64("D220"))
 
        # float read write test
        melsecNet.WriteFloat("D230", 123.456)
        printReadResult(melsecNet.ReadFloat("D230"))
 
        # double read write test
        melsecNet.WriteDouble("D240", 123.456789)
        printReadResult(melsecNet.ReadDouble("D240"))
 
        # string read write test
        melsecNet.WriteString("D250", '123456')
        printReadResult(melsecNet.ReadString("D250",3))
 
        # int16 array read write test
        melsecNet.WriteInt16("D260", [123,456,789,-1234])
        printReadResult(melsecNet.ReadInt16("D260",4))
 
        melsecNet.ConnectClose()
注意

1、每次的数据交互您都可以判断是否成功,如果您不判断,如果网络断开或是异常,会影响程序的执行。
2、读写操作支持单个数和数组。
3、支持自定义的数据读写操作。直接调用Read方法,可以读取到原生的byte数组,然后进行组合数据。

modbus_tk模块

协议

modbus协议

安装

pip install modbus_tk

测试示例
import modbus_tk
import modbus_tk.defines as cst
import modbus_tk.modbus_tcp as modbus_tcp
logger = modbus_tk.utils.create_logger("console")
if __name__ == "__main__":
    try:
        # 连接MODBUS TCP从机
        master = modbus_tcp.TcpMaster(host="192.168.0.12")
        master.set_timeout(5.0)
        print(master)
        logger.info("connected")
        # 读保持寄存器
        print(master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 40244, output_value=[20,21,22,23]))
        print('oooooo')
        demo1 = master.execute(1, cst.READ_HOLDING_REGISTERS, 40244, 9)
        print(demo1)
        print('oooooosdfsdf')
        demo2 = master.execute(1, cst.READ_HOLDING_REGISTERS, 40244, 10)
        print(demo2)
        # 读线圈寄存器
        demo3 = master.execute(1, cst.READ_COILS, 40244, 9)
    except modbus_tk.modbus.ModbusError as e:
        logger.error("%s- Code=%d" % (e, e.get_exception_code()))

生产场景使用示例

# 以下为celery定时任务的task函数,实现了使用HslCommunication模块和modbus_tk模块读取PLC设备保存的数据
import os
from datetime import datetime

from HslCommunication import MelsecMcNet
from modbus_tk import modbus_tcp, defines

from common.requests2server import approvalget
from deviceModule.models import Device, DeviceStateRecord
from publicModule.models import PLCInfoToEquipmentClause, PLCInfo, PLCBasicInfo, TransitServerInfo

from qms.celery import app


@app.task()
def get_plc_info():
    # 由于网络原因,在部分场景下服务器无法直接连通PLC设备,因此采用中转服务的方式解决该问题(中转服务读取PLC数据并保存,服务器从中转服务获取数据)
    transit_server_infos = TransitServerInfo.objects.all()
    for transit_server_info in transit_server_infos:
        if transit_server_info.server_ip and transit_server_info.server_port:
            res = approvalget(
                url=f'http://{transit_server_info.server_ip}:{transit_server_info.server_port}/plcModule/queryDeviceState/')
            if res and res.get('code') == 200:
                device_states = res.get('data', [])
                for device_state in device_states:
                    if device_state.get('device_id'):
                        devices = Device.objects.filter(id=device_state.get('device_id'))
                        if devices:
                            if devices[0].current_state not in [4, 5, 7] and \
                                    devices[0].current_state != int(device_state.get('current_state')):
                                Device.objects.filter(id=device_state.get('device_id')).update(
                                    current_state=device_state.get('current_state'))
                                DeviceStateRecord.objects.create(device_id=devices[0].id,
                                                                 state=device_state.get('current_state'),
                                                                 record_time=datetime.now())
            else:
                Device.objects.exclude(current_state__in=[4, 5, 7]).update(current_state=0)
    # 服务器可以连通PLC时,直接读取PLC数据
    plc_infos = PLCInfo.objects.filter(transit_server_info_id=None)
    for plc_info in plc_infos:
        plc_basic_info = PLCBasicInfo.objects.filter(id=plc_info.plc_basic_info_id).first()
        if plc_basic_info:
            plc_info_to_equipment_clauses = PLCInfoToEquipmentClause.objects.filter(plc_info_id=plc_info.id)
            if plc_info_to_equipment_clauses:
                if plc_basic_info.plc_protocol == 1:
                    melsec_mc_net = MelsecMcNet(plc_info.plc_ip, plc_info.plc_port)
                elif plc_basic_info.plc_protocol == 2:
                    master = modbus_tcp.TcpMaster(host=plc_info.plc_ip, port=int(plc_info.plc_port))
                for plc_info_to_equipment_clause in plc_info_to_equipment_clauses:
                    devices = Device.objects.filter(id=plc_info_to_equipment_clause.equipment_clause_id)
                    if devices:
                        current_state = devices[0].current_state
                        if plc_basic_info.plc_protocol == 1:
                            if melsec_mc_net.ConnectServer().IsSuccess:
                                run_signal = melsec_mc_net.ReadBool(plc_info_to_equipment_clause.run_signal)
                                wait_signal = melsec_mc_net.ReadBool(plc_info_to_equipment_clause.wait_signal)
                                alerting_signal = melsec_mc_net.ReadBool(plc_info_to_equipment_clause.alerting_signal)
                                if run_signal:
                                    current_state = 2
                                elif wait_signal:
                                    current_state = 1
                                elif alerting_signal:
                                    current_state = 3
                                else:
                                    current_state = 6
                            else:
                                current_state = 0
                        elif plc_basic_info.plc_protocol == 2:
                            try:
                                run_signal = master.execute(1, defines.READ_HOLDING_REGISTERS,
                                                            int(plc_info_to_equipment_clause.run_signal), 1)[0]
                                wait_signal = master.execute(1, defines.READ_HOLDING_REGISTERS,
                                                             int(plc_info_to_equipment_clause.wait_signal), 1)[0]
                                alerting_signal = master.execute(1, defines.READ_HOLDING_REGISTERS,
                                                                 int(plc_info_to_equipment_clause.alerting_signal), 1)[
                                    0]
                                if run_signal:
                                    current_state = 2
                                elif wait_signal:
                                    current_state = 1
                                elif alerting_signal:
                                    current_state = 3
                                else:
                                    current_state = 6
                            except:
                                current_state = 0
                        if devices[0].current_state not in [4, 5, 7] and devices[0].current_state != current_state:
                            devices.update(current_state=current_state)
                            DeviceStateRecord.objects.create(device_id=devices[0].id,
                                                             state=current_state,
                                                             record_time=datetime.now())
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值