dmroeder/pylogix

Error while reading data from PLC - "Response object is not subscriptable"

GaganIK22 opened this issue · 21 comments

I was trying to read data from PLC Micro 850 (Allen Bradley) through Python and dump it to MS SQL, then "Response object is not subscriptable" this error occurred while reading the data.

The below attached python program is used to read and dump data.
Micro_850_1.log

There is a import file (Mac_Data_Logger) which is been used in the above Micro_850_1 program file. That is where the error is occurring. I have even attached that file below. Can anyone please look into this and help me figure out the problem.
Mac_Data_Logger.log

The below attached is the image from the error log file.
2

It's probably your Data[0], Data[1]... which should be Data.Value[0], Data.Value[1]...

You are trying to index something that's not indexable.

after changing date[0] to data.value[0], I got a error regarding attribute -
" AttributeError: 'Response' object has no attribute 'value' "

error

Your Mac_Data_Logger.log file shows Data with capital letter "D".
And "Value" is also with capital letter "V".

So it should be exactly as I put it in my first response, Data.Value[0]...

Now I am getting "TypeError: 'NoneType' object is not subscriptable".

Can you please help me with this ?

error 1

the whole code for your reference.
Micro_850.log

Can you please post code on issue where is throwing the exception, then use code formatting.

https://docs.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks

  1. Did you try pylogix-tester to read your tags? https://github.com/TheFern2/pylogix-tester

  2. Did any of the examples work with your micro800?

I would try to play with the above tools first so you get familiarized with the Response object.

Then I would make sure that you can write a file first, then inspect that file for proper data. Once you have data, then try to import it.

Just looking at your Mac_Data_Logger.py, @GitHubDragonFly is correct.

try:
            if Driver.Read(PLC_Trigger, datatype=193):
                Data = Driver.Read(PLC_Data_Reg, 17, datatype=202)
                Driver.Write(PLC_Trigger, 0, datatype=193)
                Data_Base_Trigger = 1
                String_Value = Driver.Read(OP_Name)
                Driver.Close()
            else:
                Data_Base_Trigger = 0
                Driver.Close()
            time.sleep(0.001)
            if Data_Base_Trigger:
                cursor.execute('INSERT INTO %s\n                         (\n                                    DataAndTime\n                                    ,Value_1\n                                    ,Value_2\n                                    ,Value_3\n                                    ,Value_4\n                                    ,Value_5\n                                    ,Value_6\n                                    ,Value_7\n                                    ,Value_8\n                                    ,Value_9\n                                    ,Value_10\n                                    \n                                )\n                               Values(?,?,?,?,?,?,?,?,?,?,?)' % j, (
                 datetime.now(),
                 Data[0],
                 Data[1],
                 Data[2],
                 Data[3],
                 Data[4],
                 Data[5],
                 Data[6],
                 Data[7],
                 Data[8],
                 String_Value))
                DB_Conn.commit()
                Data_Base_Trigger = 0
            return 0
        except Exception as e:
...

This line, doesn't return an list, it returns a Response object, which contains TagName, Value, and Status. In this case Value should be the array. Data.Value[0], Data.Value[1]

Data = Driver.Read(PLC_Data_Reg, 17, datatype=202)

If you are getting None, then that means you are not reading the tag. Just FYI on micro800 you can't read program tags, only global tags. I would go back to my previous comment, and test with pylogix-tester and/or examples to make sure you are getting data.

https://github.com/TheFern2/pylogix-tester
https://github.com/dmroeder/pylogix/tree/master/examples

The easiest way:

            if Driver.Read(PLC_Trigger, datatype=193).Status == "Success":
                Data = Driver.Read(PLC_Data_Reg, 17, datatype=202).Value
                Driver.Write(PLC_Trigger, 0, datatype=193)
                Data_Base_Trigger = 1
                String_Value = Driver.Read(OP_Name).Value

Notice I added .Status to check the status of reading PLC_Trigger, then .Value for the reads. Because Read returns an object, you are trying to write the object to your database rather than the values.

@GaganIK22 any luck with this?

@dmroeder as you told in the above comment where you added 'Status to check the status of reading plc trigger, and then value to reads . I did the Same.

I got AttributeError: 'list' object has no attribute 'Value' error. below image is indicating the line of the error.
list object

below is the code with the lastest changes

if Driver.Read(PLC_Trigger, datatype=193).Status == "Success":
                Data = Driver.Read(PLC_Data_Reg, 17, datatype=202).Value
                Driver.Write(PLC_Trigger, 0, datatype=193)
                Data_Base_Trigger = 1
                String_Value = Driver.Read(OP_Name).Value
                Driver.Close()
            else:
                Data_Base_Trigger = 0
                Driver.Close()
            time.sleep(0.001)
            if Data_Base_Trigger:
                cursor.execute('INSERT INTO %s\n                         (\n                                    DataAndTime\n                                    ,Value_1\n                                    ,Value_2\n                                    ,Value_3\n                                    ,Value_4\n                                    ,Value_5\n                                    ,Value_6\n                                    ,Value_7\n                                    ,Value_8\n                                    ,Value_9\n                                    ,Value_10\n                                    \n                                )\n                               Values(?,?,?,?,?,?,?,?,?,?,?)' % j, (
                 datetime.now(),
                 Data.Value[0],
                 Data.Value[1],
                 Data.Value[2],
                 Data.Value[3],
                 Data.Value[4],
                 Data.Value[5],
                 Data.Value[6],
                 Data.Value[7],
                 Data.Value[8],
                 String_Value))
                DB_Conn.commit()
                Data_Base_Trigger = 0
            return 0
        except Exception as e:
            Data_Base_Trigger = 0
            time.sleep(delay)
            logger.error(str(IP_Address) + ' - ' + str(e))
            try:
                Driver.Close()
            except Exception as e:
                logger.error(str(IP_Address) + ' - ' + str(e))

            return 0

The way @dmroeder solution works Data is now a list with the actual values.

So you no longer need to have Data.Value[0], which I am beginning to think that Data[0].Value was the right way, I dunno getting all confused lol.

Either way try just using Data[0] like you had in your initial post.

@GaganIK22 and @TheFern2 this is confusing because we don't know what PLC_Trigger and PLC_Data_Reg are. The error described suggests that PLC_Trigger is actually a list of tags.

  • If you read a single tag, Read() will return a single instance of Response class
  • If you read a list of tags, Read() will return a list of Response class
  • If you read a single tag, which is an array, Read() will return a single instance of Response class, where .Value will be a list

We need to see the full code, where the two variables are defined.

His latest code already points to the Value:

Data = Driver.Read(PLC_Data_Reg, 17, datatype=202).Value

The best option is to print the responses in the output window, that way he knows what he is getting:

Data = Driver.Read(PLC_Data_Reg, 17, datatype=202).Value
print(Data)

or

Data = Driver.Read(PLC_Data_Reg, 17, datatype=202)
print(Data)

These print statements should be included in those parts of code wherever an error occurs.
Once he has the working solution then he can remove all the print statements.

@GitHubDragonFly His latest code points to Value for Data, but then he's trying to save to the database by saying Data.Value[0] Data doesn't have Value anymore as that's a list and the exception even says list doesn't have Value, providing all tags he's reading are arrays. If there are any tags that aren't arrays then Data will not be a list, and just a value of a single tag.

Needless to say is confusing. Just get back to basics, look at the examples. Start by reading one tag, print the response. Read an array, print the response. We're trying to fly before crawling here.

That is true since he still hasn't used any of the tools or examples to confirm whether he can actually read a value from the PLC (the sole reason for my suggesting to print the output).

As @TheFern2 told. I removed Value from Data.Value[0]. The Code is working perfectly. I am able to dump the data to the database.

I even tried printing data like @GitHubDragonFly told. print(Data[0]) I was even getting the output values in the Powershell.

I m attaching the final code below.
Mac_data_logger.txt

But I am still stuck with the Micrologix 1400, as it is showing the error can only concatenate str (not "bytes") to str.
IK we aren't using pylogix for Micrologix. But i managed to write a code for both in a single file. In case if you know how crack this please do help me and thank you for your help on the PLC Micro 850 part. It helped me a lot.

As @TheFern2 told. I removed Value from Data.Value[0]. The Code is working perfectly. I am able to dump the data to the database.

I even tried printing data like @GitHubDragonFly told. print(Data[0]) I was even getting the output values in the Powershell.

I m attaching the final code below.
Mac_data_logger.txt

But I am still stuck with the Micrologix 1400, as it is showing the error can only concatenate str (not "bytes") to str.
IK we aren't using pylogix for Micrologix. But i managed to write a code for both in a single file. In case if you know how crack this please do help me and thank you for your help on the PLC Micro 850 part. It helped me a lot.

Nice that you got it going, this library does not support Micrologix, can't help you there.

From the readme:

models like PLC5, SLC, MicroLogix are not supported. They use a different protocol, which I have no plans to support.

The protocol for PLC5, SLC and Micrologix is PCCC.

You might want to try libpccc. It's in C, so you'll have to make the bindings.

There are other libraries out there, but I'm not sure there's one for python.

There are 2 libraries that support MicroLogix in python, pycomm3 and libplctag.

Both have a GUI test utility that can be used for reading (python-GUI-pycomm3 and python-GUI-libplctag).

As for the error "can only concatenate str (not "bytes") to str", you can wrap that particular "bytes" variable with a string:

  • str(bytesVariable)

or if it's an integer value represented with bytes variable:

  • str(int.from_bytes(bytesVariable, byteorder='little'))

Thanks for the lib suggestions @evaldes2015 @GitHubDragonFly

Closing this issue as it is resolved. @GaganIK22 please open issue on respective library whichever one you choose to use, if you have issues with micrologix.

Hello.

I had another issue with the same program regarding micro 850plc.

So while i used the corrections told by you i was able to read and dump the data to sql. but the problem is that the data is getting repeated. its dumping the same values multiple times. i just wanted it to dump or some me data only when the value changes in the plc .

so if you can please help me with this. it would be usefull

@GaganIK22 That's cool that you were able to fix the issue. Regarding the repeated data that's not an issue for pylogix library.

You need to figure out how to compare your data, and do checks on your program before sending data to sql. Good luck.