[PYTHON] A class that freely changes the PLC value by socket communication

What is PLC in the first place?

PLC is a mechanical device used to operate a large machine such as a factory. This equipment is mainly manufactured by KEYENCE and Mitsubishi. When programming, it is expressed in a graphical diagram such as an electric circuit diagram instead of the English-speaking language used on a PC.

Trigger

Created at work when asked "Can a computer program communicate with a PLC?" I checked PLC from 1 because I am a person in the IT field who is not familiar with PLC.

Difficult to communicate

It seems that communication is possible, but since there are few sample codes made with python, I understand the mechanism from other languages. -Soket communication is used to send the value. -It is necessary to encode to ascii code when communicating. -The value to be entered when sending is converted from hexadecimal to decimal. You need to convert the ascii code to decimal. I had a hard time because I was not familiar with mathematics.

PLC and PC environment

It is an environment where communication is performed via a switching hub. PC-Switching Hub-PLC It's like that.

How to use this class


    ip = '10.50.100.32' #IP address on the PLC side.
    port = 8501 #Port number used for upper link communication set on the PLC side
    #The device name is EM9000 etc.
    #The number of devices is used when the number of devices is continuously and in order.
    #EM9000,Used when arranging devices such as EM9001.
    #The value / message to be entered is
       #Decimal numbers can be used as they are.
       #Hexagonal numbers can be sent in multiples of 4 characters. 4 characters, 8 characters,12 characters
       #Therefore, the number of devices also increases to 1 to 3.
       
       #Ascii can only have 2 characters per device.
    #The number of devices will increase accordingly.

    to_EM9000 = Send_to_PLC(ip,port,"EM9000","3","ABCDEF")
    to_EM9002 = Send_to_PLC(ip,port,"EM9002","2","00200616")
    to_EM9004 = Send_to_PLC(ip,port,"EM9004","1","1")


    to_EM9000.send_ascii_message()    #Send ASCII code to PLC in decimal number
    to_EM9002.send_16decimal_message() #Send to PLC from hexadecimal number to decimal number
    to_EM9004.send_10decimal_message() #Send decimal numbers to PLC as they are

Class source code

Send_to_PLC


import socket

#Class that can change the value of PLC device
class Send_to_PLC(object):

    def __init__(self,ip_address,port_num,device_name,data_length,message):
        self.ip_address =ip_address
        self.port_num = int(port_num)
        self.device_name = device_name
        self.data_length = data_length
        self.message = message

    #Convert ASCII code to decimal
    def ascii_to_10decimal(self):
        #If the number of characters in message is smaller than the specified data length
        read_device_length = int(self.data_length)
        message_length =  len(self.message)

        if read_device_length >= message_length:
            data_lng_int = message_length
        else:
            data_lng_int = read_device_length

        #Put the message in a 2-byte list.
        separate_msg_list =[]
        for i in range(data_lng_int):
            if i == 0:
                separate_msg = self.message[0:2]
                separate_msg_list.append(separate_msg)
            else:
                separate_msg = self.message[2*i:2*(i+1)]
                separate_msg_list.append(separate_msg)

        #If the number of characters is odd, the last character is left-justified.
        if len(separate_msg_list[-1]) == 1:
            separate_msg_list[-1] = separate_msg_list[-1]+ " "



        #Convert ascii code to decimal.(ascii → binary hexadecimal number → decimal number)
        digit_mesage_list = []
        for msg in separate_msg_list:
            ascii_data = msg.encode(encoding="ascii")
            hex_bina_data = binascii.hexlify(ascii_data)
            digi10_int = int(hex_bina_data,16)
            digi10_str = str(digi10_int)
            digit_mesage_list.append(digi10_str)

        trans_message = " ".join(digit_mesage_list)

        return trans_message


    #Convert hexadecimal numbers to decimal numbers
    def digit16_to_degit10(self):
        read_device_length = int(self.data_length)
        message_length =  len(self.message)

        if read_device_length >= message_length:
            data_lng_int = message_length
        else:
            data_lng_int = read_device_length


        #Divide the message into 4 bytes and put it in the list.
        #Convert hexadecimal number to decimal number after entering
        separate_msg_list =[]
        for i in range(data_lng_int):
            if i == 0:
                separate_msg = self.message[0:4]
                digi10_int = int(separate_msg,16)
                digi10_str = str(digi10_int)
                separate_msg_list.append(digi10_str)
            else:
                separate_msg = self.message[4*i:4*(i+1)]
                digi10_int = int(separate_msg,16)
                digi10_str = str(digi10_int)
                separate_msg_list.append(digi10_str)


        trans_message = " ".join(separate_msg_list)
        return trans_message


    #Send to PLC
    def send_message(self,command_list):
        command_sentence = "".join(command_list)
        s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        s.connect((self.ip_address,self.port_num))
        s.send(command_sentence.encode('ascii'))


    #After converting ASCII code to decimal number,Send to PLC
    #message is a multiple of 4 characters.
    def send_ascii_message(self):
        tranformed_digi_message = self.ascii_to_10decimal()
        command_list = ['WRS ',self.device_name,".S ",self.data_length," ",tranformed_digi_message,'\r']
        self.send_message(command_list)



    #After converting hexadecimal numbers to decimal numbers,Send to PLC
    def send_16decimal_message(self):
        tranformed_digi_message = self.digit16_to_degit10()
        command_list = ['WRS ',self.device_name,".S ",self.data_length," ",tranformed_digi_message,'\r']
        self.send_message(command_list)


    #After converting hexadecimal numbers to decimal numbers,Send to PLC
    #Supports only one device
    def send_10decimal_message(self):
        command_list = ['WR ',self.device_name,".S ",self.message,'\r']
        self.send_message(command_list)


if __name__ == '__main__':

    ip = '10.50.100.32'
    port = 8501
    #IP address when instantiating,port number,First device name, number of devices,Enter the value / message to be entered.
    to_EM9000 = Send_to_PLC(ip,port,"EM9000","3","ABCDEF")
    to_EM9002 = Send_to_PLC(ip,port,"EM9002","2","00200616")
    to_EM9004 = Send_to_PLC(ip,port,"EM9004","1","1")


    to_EM9000.send_ascii_message()    #Send ASCII code to PLC in decimal number
    to_EM9002.send_16decimal_message() #Send to PLC from hexadecimal number to decimal number
    to_EM9004.send_10decimal_message() #Send decimal numbers to PLC as they are

I feel that the explanation is not good, but I will release it for the time being.

Recommended Posts

A class that freely changes the PLC value by socket communication
A class that hits the DMM API
A memo that solves the knapsack problem by the greedy algorithm
When incrementing the value of a key that does not exist
[Python] A program that finds a pair that can be divided by a specified value
I tried to communicate with a remote server by Socket communication with Python.
Phenomenon that the numerical value changes slightly with Pandas and its response
Find the minimum value of a function by particle swarm optimization (PSO)