Testserver
The testserver was created initially for internal testing. However, you can also use the testserver to test your application. Use it when no real ADS server is available, for example during continuous integration or when TwinCAT is not installed.
You can run a basic testserver with the command:
$ python -m pyads.testserver --handler basic
The handler type defaults to ‘advanced’.
This will create a new device on 127.0.0.1 port 48898. In the next step the route to the testserver needs to be added from another python console.
>>> import pyads
>>> pyads.add_route("127.0.0.1.1.1", "127.0.0.1")
Warning
The testserver functionality was originally intended only for internal testing. The documentation and any support are not guaranteed.
Handlers
The server is a socket.socket listener, that listens to ADS-like connections and
sends responses to requests. AdsTestServer
itself does not manage the requests and responses. Those are managed by handler
classes. Currently there are two handlers available:
BasicHandler
always returns the same static responses. No data can be saved, any returned values are always 0.
AdvancedHandler
keeps a list of variables and allows for reading/writing variables. Variables need to be created upfront viaadd_variable()
.
Your requirements determine which handler is most suitable. You can also create your own handler by extending the
AbstractHandler
class. Typically, the basic handler will require the least amount
of work.
A complete overview of the capabilities of the handlers is below. If a feature is mocked, it will do nothing but no error will be thrown when it is executed. If a feature is not implemented, an error will be thrown when an attempt is made to use the feature.
Feature
(Methods from
Connection ) |
||
---|---|---|
read_state |
Mocked |
Mocked |
write_control |
Mocked |
Mocked |
read_device_info |
Mocked |
Mocked |
read |
Mocked |
Implemented |
write |
Mocked |
Implemented |
read_by_name |
Mocked |
Implemented |
read_by_name
(with handle)
|
Mocked |
Implemented |
write_by_name |
Mocked |
Implemented |
write_by_name
(with handle)
|
Mocked |
Implemented |
get_symbol |
Mocked (no info will
be found automatically)
|
Implemented |
get_all_symbols |
Mocked (list will
always be empty)
|
Implemented |
get_handle |
Mocked |
Implemented |
release_handle |
Mocked |
Mocked |
read_list_by_name |
Mocked |
Implemented |
write_list_by_name |
Mocked |
Implemented |
read_structure_by_name |
Mocked |
Not implemented |
write_structure_by_name |
Mocked |
Not implemented |
add_device_notification |
Mocked |
Implemented |
del_device_notification |
Mocked |
Implemented |
Device notifications |
Not implemented (callbacks
will never fire)
|
Implemented |
Basic Handler
The BasicHandler
just responds with 0x00 wherever possible. Trying to
read any byte or integer will always always net 0. Trying to read an LREAL
for example will give 2.09e-308, as that is the interpretation of all bits
at 0.
Actions like writing to a variable or adding a notification will always be successful, but they won’t have any effect.
Advanced Handler
The AdvancedHandler
keeps track of variables in an internal list. You can
read from and write to those variables like you would with a real server, using
either the indices, name or variable handle. Any notifications will be issued
as expected too. The handler keeps a list of variables with the type PLCVariable
.
In order to address a variable you need to explicitly create it first:
# Server code
handler = AdvancedHandler()
test_var = PLCVariable(
"Main.my_var", bytes(8), ads_type=constants.ADST_REAL64, symbol_type="LREAL"
)
handler.add_variable(test_var)
# Client code
with plc:
sym = plc.get_symbol("Main.my_var") # Already exists remotely
print(sym)
print(sym.read())