stlehmann / pyads

Python wrapper for TwinCAT ADS
MIT License
255 stars 94 forks source link

Problem with reading from testserver. #186

Closed rubanik closed 3 years ago

rubanik commented 3 years ago

Hello,

I have a problem with using the pyads.testserver. I used an example from documentation.

>>> import pyads
>>> plc = pyads.Connection('127.0.0.1.1.1', pyads.PORT_SPS1)
>>> plc.open()
>>> plc.write_by_name('global.bool_value', False, pyads.PLCTYPE_BOOL)
>>> plc.read_by_name('global.bool_value', pyads.PLCTYPE_BOOL) 

And after attempt to read my variable I get this:

2021-01-16T14:11:36+0300** Warning: Frame too long: 24>9
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.8/dist-packages/pyads/ads.py", line 825, in read_by_name
    return adsSyncReadByNameEx(
  File "/usr/local/lib/python3.8/dist-packages/pyads/pyads_ex.py", line 1033, in adsSyncReadByNameEx
    value = adsSyncReadReqEx2(
  File "/usr/local/lib/python3.8/dist-packages/pyads/pyads_ex.py", line 783, in adsSyncReadReqEx2
    raise ADSError(error_code)
pyads.pyads_ex.ADSError: ADSError: parameter size not correct (1797). 

When I write a string value (PLCTYPE_STRING) read_by_name() returns ' ' without exception.

>>> plc.write_by_name('global.string_value','Hello world', pyads.PLCTYPE_STRING)
>>> plc.read_by_name('global.string_value', pyads.PLCTYPE_STRING)
''
>>> 

Could you tell me how to solve it, or what I did wrong.

RobertoRoos commented 3 years ago

Could you share the code where you set-up the test server? There is still an older test server version floating around, and there are multiple handlers.

You can look at some of the latest tests to check the intended usage: https://github.com/stlehmann/pyads/blob/master/tests/test_symbol.py#L306

rubanik commented 3 years ago

@RobertoRoos thank you for answer.

I just followed the documentation examples and faced with this error.

  1. in the first terminal I executed python -m pyads.testserver .
  2. in the second one I started python REPL and executed lines I mentioned above.

I am a beginner in Python and maybe I don't have enough knowledge to understand how it works. It's just a hobby that I like. Now I set up VM with tc2 on board, and pyads works great. I use 'pyads' just for getting and comparing couple of parameters of my work's equipment( a lot of Backhoff stuff in my plant)

I think I should close the issue.

RobertoRoos commented 3 years ago

I think your issue is valid. If the docs suggest this should work but it doesn't, the code or docs should be changed. The sample you posted doesn't work for me either.

I checkout out the main() part of the testserver and the AdvancedHandler is being used. Since v3.3.1 it doesn't just store your written bytes but requires an actual notion of a symbol. Just the symbol name is not enough to a warrant a symbol creation, that's why the request fails. The following does work when run against the test server:

import pyads

plc = pyads.Connection('127.0.0.1.1.1', 48898)
with plc:

    plc.write(100, 1234, 3, pyads.PLCTYPE_UINT)
    val = plc.read(100, 1234, pyads.PLCTYPE_UINT)

    print(val)

But this works only because the symbols inside the testserver default to UINT8.

For more advanced usage you should create the symbols before usage on the server side:

# server.py

import pyads

var = pyads.testserver.PLCVariable(name="global.bool", ads_type=pyads.ADST_BIT, symbol_type="BOOL")

    server = AdsTestServer(handler=AdvancedHandler())
    try:
        server.add_variable(var)
        server.start()
        server.join()
    except:
        server.close()

What are other peoples thoughts on this? Should we put effort into the testserver working better automatically?

rubanik commented 3 years ago

Your code with PLCTYPE_UINT in read\write() works well. Thanks for test server example.

But if I use theread_by_name('glb.int', '100', pyads.PLCTYPE_UINT) it would fail again.

import pyads

plc = pyads.Connection('127.0.0.1.1.1', pyads.PORT_SPS1)

with plc:

    plc.write_by_name('glb.int',100, pyads.PLCTYPE_UINT)
    iVar = plc.read_by_name('glb.int', pyads.PLCTYPE_UINT)
    print(iVar)
RobertoRoos commented 3 years ago

Did you create the glb.int PLCVariable first, like in my example? If not, the test server won't know what to do with your request since it doesn't recognize the variable name.

This can only be circumvented by writing using indices (so not the variable name) with type UINT.

Typing this out loud makes it sound rather silly :p But for me the testserver had the only purpose of automated tests, where it shines.