pythonでExcel内の文字列をPLCに書込むbyMCプロトコル
いつもお世話になっております。
駆け出しIIoTエンジニアのチャオです。
本日はExcelのセルにある文字列をPLCのデータメモリに書込むプログラムを書きたいと思います。
【注意】
対象PLCはKV-7500を想定しています。
MCプロトコルを利用するので、PLCの方でMCプログラムを用いるための設定が必要な場合があります。
今回の記述では1セル内ずつの対象になります。
Excelのセルの値はPLCへ書き込む際、アスキーコードに変換します。
Excel:セルA1[ C ] ⇒ KV:DM000[0043]
1セル内の文字が2文字以上になった場合、PLCには次のデータメモリにも書き込みます
Excel:セルA1[ CIAO ] ⇒ KV:DM000[4349]DM001[414f]
※キーエンスマニュアル『KV-8000/7000/5000/3000/1000 シリーズ・KV Nano シリーズ 命令語リファレンスマニュアル-付95 ASCIIコード表一覧』参考
書き込む際は工場等で稼働中のPLCではなく、まずテスト機等で試してから行うことを推奨します。
import socket import binascii from contextlib import closing from openpyxl import load_workbook # MCプロトコル用の変換を行う際に用いる関数群 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' 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' 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プロトコルに用いるクラス class Mc: def __init__(self, ip, port, bit_or_word, device_num, device_code, data_num, word_num=0, double_word_num='00', write_list = [], device_list = []): 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 = '0000'# 今回は使わない self.bit_or_word = bit_or_word self.bit_or_word = bit_or_word 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.write_list = write_list self.device_list = device_list def excel_write_to_kv(self,load_file,read_sheet): # Excelの値を読み取る book = load_workbook(load_file)#ファイルの読込 active_sheet = book.active#ファイルのアクティブ化 read_word = active_sheet[read_sheet].value#ExcelファイルのA1に対して値を取得 ascii_change = binascii.b2a_hex(read_word.encode('utf-8')) ascii_str = str(ascii_change)[2:]# 文字列に変換し、先頭の'bを取る ascii_str = ascii_str[:-1]# 後尾の'を取る replace等を使うのもあり # 文字列が奇数だった場合は帳尻合わせのために'00'を挿入する if(len(ascii_str) / 2 % 2 == 1): ascii_str = ascii_str[:-2] + '00'+ascii_str[-2:] # 以下変数はアスキーコードを上位2桁と下位2桁反転させるために行う ascii_str_list = [ascii_str[i: i+4] for i in range(0, len(ascii_str), 4)] #返答数字を四分割にする ascii_list = [ascii_str_list[i:i+2] for i in range(0, len(ascii_str_list), 1)] # 2文字づつチャンク化 ascii_list = [ascii_list[i:i+1] for i in range(0, len(ascii_list), 1)] # 2x2文字単位にブロック化 ascii_list = [i[::2] + i[::2] for i in ascii_list] # 上下2位の値を反転させる revers_ascii_list=[] for i in ascii_list: n = (len(i) + 1)//4 s = ''.join(sum(i[n:],[])) t = s[2:4] + s[0:2] h = t revers_ascii_list.append(h) # アスキーコード変換したリストの長さを取得 revers_ascii_len = hex_change_XX(len(revers_ascii_list)) # 出力先のアドレスを指定する device_num = self.device_num#インスタンスで指定した書込み開始アドレス device_code = self.device_code#インスタンスで指定した書込み先デバイスコードDM = A8 device_list = [] for i in range(len(revers_ascii_list)): device_list.append(hex_change_XXXXXX(device_num + i) + device_code) header = '500000FFFF0300' if(self.bit_or_word == 'bit'): bit_or_word = '0100' else: bit_or_word = '0000'# ワード(ビットは0100) command = '04000214' + bit_or_word # ランダム書込みワード word_num = hex_change_XX(len(revers_ascii_list))#ワードの書込み点数 w_word_num = '00' #ダブルワードの書込み点数。今回は使わない設定なので'00' command_protocol = command + word_num + w_word_num for i in range(len(revers_ascii_list)): command_protocol += device_list[i] + revers_ascii_list[i] 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(1024) res_data=binascii.b2a_hex(res_data) res_data=res_data.decode() error_check(res_data[18:22]) except: print('write error') mc_send = Mc(ip = '192.168.0.140', port = 5000, bit_or_word = 'word', # 'word' or 'bit' device_num = 100, # アドレス device_code = 'A8', # デバイスコード data_num = 10) # データ数 今回は使わない # load_fileには本プログラムと同じディレクトリ内のExcelファイルを想定しています。 # r"./07_20/sample.xlsx"でもファイル指定が可能かと思います。 # read_sheetにはload_fileの書き込みたい文字列が入ったセルを指定します。 mc_send.excel_write_to_kv(load_file = 'sample.xlsx',read_sheet='A1')