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