dmroeder / pylogix

Read/Write data from Allen Bradley Compact/Control Logix PLC's
Apache License 2.0
599 stars 182 forks source link

Other attributes #98

Closed TechLKL closed 1 year ago

TechLKL commented 4 years ago

Hi dmroeder

Nice project.

Do you have a list of attributes of the rockwell modules? Or how do you know which attributenumber is for what?

dmroeder commented 4 years ago

Look at the file lgxDevice.py

TechLKL commented 4 years ago

I am sorry for my very unclear question. What I meant was: for example the “Get PLC time” function. Here you type in servicetype, class, attribute etc.

I guess this is the same information you pass into a message instruction? Or am I mistaken?

If then I would like to get e.g. “Grand Master Clock Priority”. How do I find out which values to use for class, servicetype, attribute etc.?

def _getPLCTime(self, raw=False):
        """
        Requests the PLC clock time
        """
        if not self._connect():
            return None

        AttributeService = 0x03
        AttributeSize = 0x02
        AttributeClassType = 0x20
        AttributeClass = 0x8B
        AttributeInstanceType = 0x24
        AttributeInstance = 0x01
        AttributeCount = 0x01
        TimeAttribute = 0x0B

        AttributePacket = pack('<BBBBBBH1H',
                               AttributeService,
                               AttributeSize,
                               AttributeClassType,
                               AttributeClass,
                               AttributeInstanceType,
                               AttributeInstance,
                               AttributeCount,
                               TimeAttribute)

        eip_header = self._buildEIPHeader(AttributePacket)
        status, ret_data = self._getBytes(eip_header)

        if status == 0:
            # get the time from the packet
            plc_time = unpack_from('<Q', ret_data, 56)[0]
            if raw:
                value = plc_time
            human_time = datetime(1970, 1, 1) + timedelta(microseconds=plc_time)
            value = human_time
        else:
            value = None

        return Response(None, value, status)
dmroeder commented 4 years ago

Ahh, I see. Well there is no one stop place that describes all of those services/classes/attributes. I pieced together what I've done with a few documents that I've found and a lot of time with Wireshark.

I doubt that object is documented, the only way I know of is to capture RSLinx retrieving that information via wireshark. This can be tricky to do for 2 reasons. First, when you are online with a PLC and capturing with wireshark, there will be a massive amount of packets. It's time consuming to isolate the packet that you are looking for. Many of the services are undocumented, so you will have a sea of unknown information, you have to somehow rule out the ones that are not what you are after.

The Second reason is because RSLinx has the ability to hide the responses because it can access packets via the network stack, prior to wireshark accessing them. I bought a sharktap, which helped me understand some of these packets. This has it's own difficulties, in that I now need 2 computers. One running Logix/RSLinx to generate packets to capture, another that is not running RSLinx so that I can capture the packets with my sharktap.

One thing I worked out using wireshark was discovering devices on the network. With wireshark running, I added a new Ethernet I/P driver, then watched what happened. This was relatively easy because only RSLinx was running, no RSLogix online, so there was much less data to try to sift through. Another was retrieving module properties. I could start wireshark just before I requested a modules properties using RSLinx, minimizing the amount of packets I would have to look through.

I have no method for you to provide custom service/class/instance/attribute so even if you knew those parameters, there would be a bit of code to write, including parsing the response. Originally, was simply focused on reading/writing, the rest came later.

TechLKL commented 4 years ago

Thank for your very elaborate answer.

Sounds like it is way more tricky than i first expected. I am not that into how EIP works in depth.

I thought i could use the below data and replace them with the data in your "Get PLC Time" function. But i guess it takes more than that.

image

dmroeder commented 4 years ago

I have considered adding a method to send user defined CIP commands, though I've been reluctant because I know it will be a new source of raised issues and there will be a sharp increase in requests to help with "XYZ CIP object". I just don't the time to investigate all of the possibilities out there. Plus, it goes way beyond what I ever planned for this project. The amount of time I spend helping others on github, forums and email is sustainable right now, the wrong can of worms will make this not very much fun :)

Send me an email.