chao_demiglaceのブログ

工場でPLCに対してのデータ収集等を行っています。

pythonでPLCのビットをONするbyMCプロトコル通信

いつもお世話になっております。
駆け出しIIoTエンジニアのチャオです。

前回、MCプロトコルでのデータ読出しを行いましたが、
今回はビットに対してON/OFFの書出しを行います。
想定しているPLCはキーエンスのKV-7500です。

import socket
import binascii
from contextlib import closing

"""
### MCプロトコルについて ###

#####################################
〇フォーマット
	サブヘッダ	5000
	ネットワーク番号00
	PC番号		FF
	要求ユニット	FF03
	要求先ユニット	00
	要求データ長	XXXX
	CPU監視タイマ	0000
	コマンド	0304#ランダム読出し
	サブコマンド	0000
######################################
〇コマンド一覧
・一括読み出し
	ビット:0401 0001 →01040100
	ワード:0401 0000 →01040000
・一括書き込み
	ビット:1401 0001 →01140100
	ワード:1401 0000 →01140000

・ランダム読出し
	ワード:0403 0000 →03040000
・ランダム書き込み
	ビット:1402 0001 →02140100
	ワード:1402 0000 →02140000

・モニタ登録
	:0801 0000 →01080000
・モニタ読出し
 	:0802 0000 →02080000

・複数ブロック一括読み出し
	ワード:0406 0000 →06040000
・複数ブロック一括書き込み
	ワード:1406 0000 →06140000

・バッファメモリ読出し
	ワード:0613 0000 →13060000
・バッファメモリ読出し
	ワード:0613 0000 →13060000

・インテリユニットバッファメモリ読出し
	ワード:0601 0000 →01060000
・インテリユニットバッファメモリ書き込み
	ワード:0601 0000 →01060000

・リモートRUN
 	:1001 0000 →01100000
・リモートSTOP
 	:1002 0000 →02100000

・CPU形名読み出し
 	:0101 0000 →01010000
・折り返しテスト
 	:0619 0000 →19060000

#########################################
〇デバイスコード
	リレー		9C
	リンクリレー	A0
	内部補助リレー	90
	ラッチリレー	92
	コントロールリレー	91
	コントロールメモリ	A9
	データメモリ	A8
	拡張データメモリ	A8
	ファイルレジスタ	AF
				B0
	リンクレジスタ	B4
	タイマ(現在値)	C2
	タイマ(接点)	C1
	カウンタ(現在値)	C5
	カウンタ(接点)		C4
###########################################

〇一括書出し
	サブヘッダ		5000
	ネットワーク番号	00
	PC番号			FF
	I/O番号			FF03
	局番			        00
        データ長                 XXXX
	監視タイマ		0400
	コマンド		        0114
	サブコマンド		0100#ビット対象は0100
	デバイス番号		XXXXXX(3なら030000)
	デバイス種類		90# 内部補助リレー MR
	デバイス点数		XXXX(1点なら0100)
  ONOFF制御     10 #デバイス点数が奇数と偶数では多少変わってくる。今回のような奇数の場合はこちらで先頭がON
	5000,00,FF,FF03,0D00,0400,0114,0100,010000,90,0100,10
	→MR1に対してON制御を行うコマンド

"""

class Mc:
    def __init__(self,
                 ip,
                 port,
                 bit_or_word,
                 device_num,
                 device_code,
                 data_num,
                 word_num='00',
                 double_word_num='00',
                 bit_on_off='00'):
        self.ip = ip
        self.port = port
        self.subhead = '5000'
        self.network = '00'
        self.pc_num = 'FF'
        self.i_o_num = 'FF03'
        self.office_num = '00'
        self.monitoring_timer = '0400'
        self.bit_or_word = bit_or_word
        if(self.bit_or_word == 'bit'):
            sub_command = '0100'
        else:
            sub_command = '0000'# ワード(ビットは0100)
        self.device_num = device_num
        self.device_code = device_code
        self.data_num = data_num
        self.word_num = word_num
        self.double_word_num = double_word_num
        self.bit_on_off = bit_on_off

    # 一括書出し
    # レスポンスはエラーコード等
    def pin_write(self):
        header = '500000FFFF0300'
        command = self.monitoring_timer + '0114' + sub_command 
        #command = self.monitoring_timer + '01140100'
        #device = self.device_num + self.device_code #インタンスを使う場合はこちらをCIで下行をCO
        device = '01000090'# MR001指定の場合
        #number = self.data_num +self.bit_on_off #インタンスを使う場合はこちらをCIで下行をCO
        number = '0100'+'10'
        command_protocol = command + device + number
        code_num = hex_change_XXXX(str(round(len(command_protocol)/2)))
        _send = header + code_num + command_protocol
        print(_send)
        mc_send=binascii.a2b_hex(_send)
        sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        with closing(sock):
            try:
                sock.connect((self.ip,self.port))
                sock.send(mc_send)
                res_data=sock.recv(4096)
                res_data=binascii.b2a_hex(res_data)
                res_data=res_data.decode()
                error_check(res_data[18:22])
            except:
                print('write error')
        # ONしたものをOFFする
        #number = self.data_num +self.bit_on_off #インタンスを使う場合はこちらをCIで下行をCO
        number = '0100'+'00'
        command_protocol = command + device + number
        code_num = hex_change_XXXX(str(round(len(command_protocol)/2)))
        _send = header + code_num + command_protocol
        mc_send=binascii.a2b_hex(_send)
        sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        with closing(sock):
            try:
                sock.connect((self.ip,self.port))
                sock.send(mc_send)
                res_data=sock.recv(4096)
                res_data=binascii.b2a_hex(res_data)
                res_data=res_data.decode()
                error_check(res_data[18:22])
            except:
                print('write error')

def hex_change_XX(num):
    if(type(num)==str):
        num_int=int(num)
    else:
        num_int=num
    num=hex(num_int)
    num=num[2:4]
    if(num_int<=15):
        num='0'+num
    return num
def hex_change_XXXX(data):
    if(type(data)==str):
        data_int=int(data)
    else:
        data_int=data
    data=hex(data_int)
    if(data_int<=15):
        data='0'+data[2:]+'00'#語尾の00はビット指定の時に用いるためチャネルでは00固定
    if(data_int<=255 and data_int>15):
        data=data[2:]+'00'
    if(data_int>255 and data_int<=4095):
        data=data[3:5]+'0'+data[2:3]
    if(data_int>4095 and data_int<=65535):
        data=data[4:6]+data[2:4]
    return data
def hex_change_XXXXXX(data):
    if(type(data)==str):
        data_int=int(data)
    else:
        data_int=data
    data=hex(data_int)
    if(data_int<=15):
        data='0'+data[2:]+'0000'#語尾の00はビット指定の時に用いるためチャネルでは00固定
    if(data_int<=255 and data_int>15):
        data=data[2:]+'0000'
    if(data_int>255 and data_int<=4095):
        data=data[3:5]+'0'+data[2:3]+'00'
    if(data_int>4095 and data_int<=65535):
        data=data[4:6]+data[2:4]+'00'
    if(data_int > 65535 and data_int <= 1048575):
        data=data[5:7]+data[3:5]+'0'+data[2:3]
    if(data_int > 1048575):
        data=data[6:8] + data[4:6] + data[2:4]
    return data
def error_check(error_code):
    if(error_code=='0000'):
        return
    else:
        print('errorコードのレスポンスがありました。'+error_code)

mc_send = Mc(ip = '192.168.0.140',
             port = 5000,
             bit_or_word = 'bit',# 'word' or 'bit'
             device_num = 1,# アドレス
             device_code = '90',
             data_num = 1
             bit_on_off = '10')# 対象数

mc_send.pin_write()# ビットのONとOFF