Skip to content

Commit fbdc470

Browse files
authored
Pymodbus v2.3.0 (#452)
* Rebase to dev3.7 * Adding 3.7 to travis configuration * Updated documentation to resolve warnings introduced with the longer names Updated requirements-docs.txt to include missing modules * Fixed reference to deprecated asynchronous * Adding gmp disable to fix pypy build issues * Adding gmp disable to fix pypy build issues * Removing travis python 3.7 configuration Commenting out python3.7 from Travis while waiting for support. You can run teh 3.7 tests with tox without issues * Adding asserts for Payload Endianness * Fixing example of Payload. Same Endianness for builder and decoder. * Fix Sql db slave context validate and get methods - #139 * #353 - debugging, Add debug logs to check size of avaialble data in read buffer * #353 Provide an option to disable inter char timeouts * #353 Bump version, update changelog * check self.socket (#354) * check self.socket self.socket might be None at this point * Update pymodbus/client/sync.py Co-Authored-By: mpf82 <mpf82@users.noreply.github.com> * Fix typo (#378) * Pymodbus 2.2.0 (#375) * #357 Support registration of custom requests * #368 Fixes write to broadcast address When writing to broadcast address (unit_id=0) there should be no response according to the Modbus spec. This fix changes expected_response_length to 0 when writing to unit_id=0. This will break any existing code that is improperly using unit_id 0 for a slave address. * Bump version to 2.2.0 Fix #366 Update failures in sql context Update Changelog Fix major minor version in example codes * Fix #371 pymodbus repl on python3 * 1. Fix tornado async serial client `TypeError` while processing incoming packet. 2. Fix asyncio examples. 3. Minor update in factory.py, now server logs prints received request instead of only function cod * [fix v3] poprawa sprawdzania timeout * Release candidate for pymodbus 2.2.0 * Fix #377 when invalid port is supplied and minor updates in logging * #368 adds broadcast support for sync client and server Adds broadcast_enable parameter to client and server, default value is False. When true it will treat unit_id 0 as broadcast and execute requests on all server slave contexts and not send a response and on the client side will send the request and not try to receive a response. * #368 Fixes minor bug in broadcast support code * Fixed erronous CRC handling If the CRC recieved is not correct in my case my slave got caught in a deadlock, not taking any new requests. This addition fixed that. * Update Changelog * Fix test coverage * Fix #387 Transactions failing on 2.2.0rc2. * Task Cancellation and CRC Errors Alternate solution for #356 and #360. Changes the RTU to make the transaction ID as the unit ID instead of an ever incrementing number. Previously this transaction ID was always 0 on the receiving end but was the unique transaction ID on sending. As such the FIFO buffer made the most sense. By tying it to the unit ID, we can recover from failure modes such as: - - Asyncio task cancellations (eg. timeouts) #360 - Skipped responses from slaves. (hangs on master #360) - CRC Errors #356 - Busy response * Cherry pick commit from PR #367 , Update changelog , bump version to 2.2.0rc4 * #389 Support passing all serial port parameters to asynchronous server * Fix BinaryPayloadDecoder and Builder wrt to coils * Misc updates, bump version to 2.2.0 * ReportSlaveIdResponse now tries to get slave id based on server identity for pymodbus servers * Update missing bcrypt requirement for testing * Fix docs (#407) * Fix document generation * Formatting updates in Changelog * Remove pycrypto dep (#411) It has not been needed by Twisted for a long time, and has been unmaintained for a long time. * Fix --upgrade option in install dependencies (#413) * Fix document generation * Formatting updates in Changelog * Fix --upgrade option in install dependencies * Padding for odd sized responses (#425) If the response is odd size the buffer needs to be padded with an additional byte. * README update: REPL stands for Read Evaluate **Print** Loop (#426) * Drop python 3.4 support (#440) Python 3.4 is EoL and has an easy upgrade path to 3.5+. Support was dropped in Twisted 19.7.0, which is causing Travis to fail pymodbus tests for 3.4. * Re-enable travis python 3.7 builds (#441) * Update __init__.py (#436) * Use SPDX identifier to specify the exact license type (#427) * asyncio server implementation (#400) * #357 Support registration of custom requests * #368 Fixes write to broadcast address When writing to broadcast address (unit_id=0) there should be no response according to the Modbus spec. This fix changes expected_response_length to 0 when writing to unit_id=0. This will break any existing code that is improperly using unit_id 0 for a slave address. * Bump version to 2.2.0 Fix #366 Update failures in sql context Update Changelog Fix major minor version in example codes * Fix #371 pymodbus repl on python3 * 1. Fix tornado async serial client `TypeError` while processing incoming packet. 2. Fix asyncio examples. 3. Minor update in factory.py, now server logs prints received request instead of only function cod * [fix v3] poprawa sprawdzania timeout * Release candidate for pymodbus 2.2.0 * Fix #377 when invalid port is supplied and minor updates in logging * #368 adds broadcast support for sync client and server Adds broadcast_enable parameter to client and server, default value is False. When true it will treat unit_id 0 as broadcast and execute requests on all server slave contexts and not send a response and on the client side will send the request and not try to receive a response. * #368 Fixes minor bug in broadcast support code * Fixed erronous CRC handling If the CRC recieved is not correct in my case my slave got caught in a deadlock, not taking any new requests. This addition fixed that. * Update Changelog * Fix test coverage * Fix #387 Transactions failing on 2.2.0rc2. * Task Cancellation and CRC Errors Alternate solution for #356 and #360. Changes the RTU to make the transaction ID as the unit ID instead of an ever incrementing number. Previously this transaction ID was always 0 on the receiving end but was the unique transaction ID on sending. As such the FIFO buffer made the most sense. By tying it to the unit ID, we can recover from failure modes such as: - - Asyncio task cancellations (eg. timeouts) #360 - Skipped responses from slaves. (hangs on master #360) - CRC Errors #356 - Busy response * Cherry pick commit from PR #367 , Update changelog , bump version to 2.2.0rc4 * native asyncio implementation of ModbusTcpServer and ModbusUdpServer * preliminary asyncio server examples * move serial module dependency into class instantiation * unittests for asyncio based server implementation * induce exception in execute method by mock patching the request object's execute method * move serial module dependency into class instantiation * added asynctest depency to requirements-tests.txt * add unittest skip condition for unsupported targets, remove failing assertion from unsupported targets, use lower asynctest version * remove logger setLevel call since doing so may override library consumers' already set log level * remove async def/await keywords from unittest so that the ast can be loaded in py2 even if the test is to be skipped * Add option to repl allowing Modbus RTU framing on a TCP socket (#447) * repl: Allow Modbus RTU framing on a TCP socket * repl: Update README for framing option * Fix asynci server test failures on python3.6 and below * Bump version to 2.2.0rc1, update six requirements and Changelog * Support multiple Python versions to fix test error from PR #400 (#444) * client/sync.py: Fix missing serial module dependency The serial.connect failed in PR riptideio#400 with "NameError: name 'serial' is not defined" [1]: self = <ModbusSerialClient at 0x7fcda4009b00 socket=None, method=ascii, timeout=3> def connect(self): """ Connect to the modbus serial server :returns: True if connection succeeded, False otherwise """ if self.socket: return True try: > self.socket = serial.Serial(port=self.port, timeout=self.timeout, bytesize=self.bytesize, stopbits=self.stopbits, baudrate=self.baudrate, parity=self.parity) E NameError: name 'serial' is not defined pymodbus/client/sync.py:476: NameError This patch moves the serial import back to the head. [1] https://travis-ci.org/riptideio/pymodbus/jobs/566009109 Fixes: commit e6da559 asyncio server implementation (#400) * server/asyncio.py: Create server with appropriate args and environment If Python is older than 3.7, the create_server will fail like PR riptideio#400 with "unexpected keyword argument 'start_serving'" [1] which is new in Python version 3.7: self.server_factory = self.loop.create_server(lambda :self.handler(self), *self.address, reuse_address=allow_reuse_address, reuse_port=allow_reuse_port, backlog=backlog, > start_serving=not defer_start) E TypeError: create_server() got an unexpected keyword argument 'start_serving' pymodbus/server/asyncio.py:400: TypeError This patch creates server according to Python environment. [1] https://travis-ci.org/starnight/pymodbus/jobs/584178484 Fixes: commit e6da559 asyncio server implementation (#400) * Create asyncio task with appropriate method and environment If Python is older than 3.7, the asyncio.create_task will fail like PR riptideio#400 with "AttributeError: module 'asyncio' has no attribute 'create_task'" [1] which is new in Python version 3.7 [2]: @asyncio.coroutine def testTcpServerCloseActiveConnection(self): ''' Test server_close() while there are active TCP connections''' data = b"\x01\x00\x00\x00\x00\x06\x01\x01\x00\x00\x00\x01" server = yield from StartTcpServer(context=self.context,address=("127.0.0.1", 0),loop=self.loop) > server_task = asyncio.create_task(server.serve_forever()) E AttributeError: module 'asyncio' has no attribute 'create_task' test/test_server_asyncio.py:205: AttributeError This patch creates task according to Python environment. [1] https://travis-ci.org/starnight/pymodbus/jobs/584193587 [2] https://docs.python.org/3/library/asyncio-task.html#creating-tasks Fixes: commit e6da559 asyncio server implementation (#400) * server/asyncio.py: Fix format string for older Python If Python is older than 3.6, f-Strings will fail like PR riptideio#400 with "SyntaxError: invalid syntax" [1] which is new in Python version 3.6 with PEP 498 -- Literal String Interpolation [2]: test/test_server_asyncio.py:14: in <module> from pymodbus.server.asyncio import StartTcpServer, StartUdpServer, StartSerialServer, StopServer, ModbusServerFactory E File "/home/travis/build/starnight/pymodbus/pymodbus/server/asyncio.py", line 424 E _logger.warning(f"aborting active session {k}") E ^ E SyntaxError: invalid syntax This patch fixes the format string with traditional format string syntax. [1] https://travis-ci.org/starnight/pymodbus/jobs/584427976 [2] https://www.python.org/dev/peps/pep-0498/ Fixes: commit e6da559 asyncio server implementation (#400) * test: Make assert_called_once() test only with Python 3.6+ If Python is older than 3.6, unittest.mock.assert_called_once() will fail like PR riptideio#400 with "AttributeError: assert_called_once" [1] which is new in Python version 3.6 [2]: > self.loop.create_server.assert_called_once() test/test_server_asyncio.py:76: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = <CoroutineMock name='mock.create_server' id='139638313234784'> name = 'assert_called_once' def __getattr__(self, name): if name in {'_mock_methods', '_mock_unsafe'}: raise AttributeError(name) elif self._mock_methods is not None: if name not in self._mock_methods or name in _all_magics: raise AttributeError("Mock object has no attribute %r" % name) elif _is_magic(name): raise AttributeError(name) if not self._mock_unsafe: if name.startswith(('assert', 'assret')): > raise AttributeError(name) E AttributeError: assert_called_once /opt/python/3.5.6/lib/python3.5/unittest/mock.py:585: AttributeError This patch skips the tests if they are not in Python 3.6+. [1] https://travis-ci.org/starnight/pymodbus/jobs/584431003 [2] https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.assert_called_once Fixes: commit e6da559 asyncio server implementation (#400) * test: Make serve_forever() test only with Python 3.7+ If Python is older than 3.7, asyncio.base_events.Server.serve_forever will fail like PR riptideio#400 with "AttributeError: <class 'asyncio.base_events.Server'> does not have the attribute 'serve_forever'" [1] which is new in Python version 3.7 [2]: @asyncio.coroutine def testTcpServerServeNoDefer(self): ''' Test StartTcpServer without deferred start (immediate execution of server) ''' > with patch('asyncio.base_events.Server.serve_forever', new_callable=asynctest.CoroutineMock) as serve: test/test_server_asyncio.py:81: ... if not self.create and original is DEFAULT: raise AttributeError( > "%s does not have the attribute %r" % (target, name) ) E AttributeError: <class 'asyncio.base_events.Server'> does not have the attribute 'serve_forever' This patch skips the tests if they are not in Python 3.7+. [1] https://travis-ci.org/starnight/pymodbus/jobs/584212511 [2] https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.Server.serve_forever Fixes: commit e6da559 asyncio server implementation (#400) * Add TLS feature for Modbus synchronous (#446) * Add TLS feature for Modbus synchronous Modbus.org released MODBUS/TCP Security Protocol Specification [1], which focuses variant of the Mobdbus/TCP protocol utilizing Transport Layer Security (TLS). This patch enables the Modbus over TLS feature as ModbusTlsClient with the Python builtin module ssl - TLS/SSL wrapper for socket objects. [1]: http://modbus.org/docs/MB-TCP-Security-v21_2018-07-24.pdf * Implement MODBUS TLS synchronous server Since we have the MODBUS TLS synchronous client, we can also have the MODBUS TLS synchronous server. * Fix #461 - Udp client/server , Fix #401 - package license with source, #457 Fix typo's in docstrings, #455-Support float16 * Fix examples, Merge #431 * #401 Move license to root folder from docs
1 parent 31c1650 commit fbdc470

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2251
-55
lines changed

.coveragerc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[run]
22
omit =
33
pymodbus/repl/*
4-
pymodbus/internal/*
4+
pymodbus/internal/*
5+
pymodbus/server/asyncio.py

.travis.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@ matrix:
44
include:
55
- os: linux
66
python: "2.7"
7-
- os: linux
8-
python: "3.4"
97
- os: linux
108
python: "3.5"
119
- os: linux
1210
python: "3.6"
13-
# - os: linux
14-
# python: "3.7"
11+
- os: linux
12+
python: "3.7"
1513
- os: osx
1614
osx_image: xcode8.3
1715
language: generic

CHANGELOG.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
Version 2.3.0
2+
-----------------------------------------------------------
3+
* Support Modbus TLS (client / server)
4+
* Distribute license with source
5+
* BinaryPayloadDecoder/Encoder now supports float16 on python3.6 and above
6+
* Fix asyncio UDP client/server
7+
* Minor cosmetic updates
8+
9+
Version 2.3.0rc1
10+
-----------------------------------------------------------
11+
* Asyncio Server implementation (Python 3.7 and above only)
12+
* Bug fix for DiagnosticStatusResponse when odd sized response is received
13+
* Remove Pycrypto from dependencies and include cryptodome instead
14+
* Remove `SIX` requirement pinned to exact version.
15+
* Minor bug-fixes in documentations.
16+
17+
118
Version 2.2.0
219
-----------------------------------------------------------
320
**NOTE: Supports python 3.7, async client is now moved to pymodbus/client/asychronous**
File renamed without changes.

MANIFEST.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
include requirements.txt
22
include README.rst
3-
include CHANGELOG.rst
3+
include CHANGELOG.rst
4+
include LICENSE

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ get lost in the noise: http://groups.google.com/group/pymodbus or
9999
at gitter: https://gitter.im/pymodbus_dev/Lobby
100100

101101
------------------------------------------------------------
102-
Pymodbus REPL (Read Evaluate Procee Loop)
102+
Pymodbus REPL (Read Evaluate Print Loop)
103103
------------------------------------------------------------
104104
Starting with Pymodbus 2.x, pymodbus library comes with handy
105105
Pymodbus REPL to quickly run the modbus clients in tcp/rtu modes.
@@ -205,4 +205,4 @@ Pymodbus is built on top of code developed from/by:
205205
* Hynek Petrak, https://github.com/HynekPetrak
206206
* Twisted Matrix
207207

208-
Released under the BSD License
208+
Released under the `BSD License <LICENSE>`_

doc/source/library/REPL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Depends on [prompt_toolkit](https://python-prompt-toolkit.readthedocs.io/en/stab
66

77
Install dependencies
88
```
9-
$ pip install click prompt_toolkit --upgarde
9+
$ pip install click prompt_toolkit --upgrade
1010
```
1111

1212
Or

examples/common/async_asyncio_client.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
# Import the required asynchronous client
1717
# ----------------------------------------------------------------------- #
1818
from pymodbus.client.asynchronous.tcp import AsyncModbusTCPClient as ModbusClient
19-
# from pymodbus.client.asynchronous.udp import (
20-
# AsyncModbusUDPClient as ModbusClient)
19+
from pymodbus.client.asynchronous.udp import (
20+
AsyncModbusUDPClient as ModbusClient)
2121
from pymodbus.client.asynchronous import schedulers
2222

2323
else:
@@ -141,6 +141,7 @@ def run_with_not_running_loop():
141141
log.debug("------------------------------------------------------")
142142
loop = asyncio.new_event_loop()
143143
assert not loop.is_running()
144+
asyncio.set_event_loop(loop)
144145
new_loop, client = ModbusClient(schedulers.ASYNC_IO, port=5020, loop=loop)
145146
loop.run_until_complete(start_async_test(client.protocol))
146147
loop.close()
@@ -191,9 +192,12 @@ def run_with_no_loop():
191192
ModbusClient Factory creates a loop.
192193
:return:
193194
"""
195+
log.debug("---------------------RUN_WITH_NO_LOOP-----------------")
194196
loop, client = ModbusClient(schedulers.ASYNC_IO, port=5020)
195197
loop.run_until_complete(start_async_test(client.protocol))
196198
loop.close()
199+
log.debug("--------DONE RUN_WITH_NO_LOOP-------------")
200+
log.debug("")
197201

198202

199203
if __name__ == '__main__':
@@ -207,5 +211,5 @@ def run_with_no_loop():
207211

208212
# Run with already running loop
209213
run_with_already_running_loop()
210-
log.debug("---------------------RUN_WITH_NO_LOOP-----------------")
214+
211215
log.debug("")

examples/common/asynchronous_server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def run_async_server():
108108
identity.VendorUrl = 'http://github.com/bashwork/pymodbus/'
109109
identity.ProductName = 'Pymodbus Server'
110110
identity.ModelName = 'Pymodbus Server'
111-
identity.MajorMinorRevision = '2.2.0'
111+
identity.MajorMinorRevision = '2.3.0'
112112

113113
# ----------------------------------------------------------------------- #
114114
# run the server you want

examples/common/asyncio_server.py

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#!/usr/bin/env python
2+
"""
3+
Pymodbus Asyncio Server Example
4+
--------------------------------------------------------------------------
5+
6+
The asyncio server is implemented in pure python without any third
7+
party libraries (unless you need to use the serial protocols which require
8+
asyncio-pyserial). This is helpful in constrained or old environments where using
9+
twisted is just not feasible. What follows is an example of its use:
10+
"""
11+
# --------------------------------------------------------------------------- #
12+
# import the various server implementations
13+
# --------------------------------------------------------------------------- #
14+
import asyncio
15+
from pymodbus.server.asyncio import StartTcpServer
16+
from pymodbus.server.asyncio import StartUdpServer
17+
from pymodbus.server.asyncio import StartSerialServer
18+
19+
from pymodbus.device import ModbusDeviceIdentification
20+
from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSparseDataBlock
21+
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
22+
23+
from pymodbus.transaction import ModbusRtuFramer, ModbusBinaryFramer
24+
# --------------------------------------------------------------------------- #
25+
# configure the service logging
26+
# --------------------------------------------------------------------------- #
27+
import logging
28+
FORMAT = ('%(asctime)-15s %(threadName)-15s'
29+
' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
30+
logging.basicConfig(format=FORMAT)
31+
log = logging.getLogger()
32+
log.setLevel(logging.DEBUG)
33+
34+
35+
async def run_server():
36+
# ----------------------------------------------------------------------- #
37+
# initialize your data store
38+
# ----------------------------------------------------------------------- #
39+
# The datastores only respond to the addresses that they are initialized to
40+
# Therefore, if you initialize a DataBlock to addresses of 0x00 to 0xFF, a
41+
# request to 0x100 will respond with an invalid address exception. This is
42+
# because many devices exhibit this kind of behavior (but not all)::
43+
#
44+
# block = ModbusSequentialDataBlock(0x00, [0]*0xff)
45+
#
46+
# Continuing, you can choose to use a sequential or a sparse DataBlock in
47+
# your data context. The difference is that the sequential has no gaps in
48+
# the data while the sparse can. Once again, there are devices that exhibit
49+
# both forms of behavior::
50+
#
51+
# block = ModbusSparseDataBlock({0x00: 0, 0x05: 1})
52+
# block = ModbusSequentialDataBlock(0x00, [0]*5)
53+
#
54+
# Alternately, you can use the factory methods to initialize the DataBlocks
55+
# or simply do not pass them to have them initialized to 0x00 on the full
56+
# address range::
57+
#
58+
# store = ModbusSlaveContext(di = ModbusSequentialDataBlock.create())
59+
# store = ModbusSlaveContext()
60+
#
61+
# Finally, you are allowed to use the same DataBlock reference for every
62+
# table or you may use a separate DataBlock for each table.
63+
# This depends if you would like functions to be able to access and modify
64+
# the same data or not::
65+
#
66+
# block = ModbusSequentialDataBlock(0x00, [0]*0xff)
67+
# store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)
68+
#
69+
# The server then makes use of a server context that allows the server to
70+
# respond with different slave contexts for different unit ids. By default
71+
# it will return the same context for every unit id supplied (broadcast
72+
# mode).
73+
# However, this can be overloaded by setting the single flag to False and
74+
# then supplying a dictionary of unit id to context mapping::
75+
#
76+
# slaves = {
77+
# 0x01: ModbusSlaveContext(...),
78+
# 0x02: ModbusSlaveContext(...),
79+
# 0x03: ModbusSlaveContext(...),
80+
# }
81+
# context = ModbusServerContext(slaves=slaves, single=False)
82+
#
83+
# The slave context can also be initialized in zero_mode which means that a
84+
# request to address(0-7) will map to the address (0-7). The default is
85+
# False which is based on section 4.4 of the specification, so address(0-7)
86+
# will map to (1-8)::
87+
#
88+
# store = ModbusSlaveContext(..., zero_mode=True)
89+
# ----------------------------------------------------------------------- #
90+
store = ModbusSlaveContext(
91+
di=ModbusSequentialDataBlock(0, [17]*100),
92+
co=ModbusSequentialDataBlock(0, [17]*100),
93+
hr=ModbusSequentialDataBlock(0, [17]*100),
94+
ir=ModbusSequentialDataBlock(0, [17]*100))
95+
96+
context = ModbusServerContext(slaves=store, single=True)
97+
98+
# ----------------------------------------------------------------------- #
99+
# initialize the server information
100+
# ----------------------------------------------------------------------- #
101+
# If you don't set this or any fields, they are defaulted to empty strings.
102+
# ----------------------------------------------------------------------- #
103+
identity = ModbusDeviceIdentification()
104+
identity.VendorName = 'Pymodbus'
105+
identity.ProductCode = 'PM'
106+
identity.VendorUrl = 'http://github.com/riptideio/pymodbus/'
107+
identity.ProductName = 'Pymodbus Server'
108+
identity.ModelName = 'Pymodbus Server'
109+
identity.MajorMinorRevision = '2.3.0'
110+
111+
# ----------------------------------------------------------------------- #
112+
# run the server you want
113+
# ----------------------------------------------------------------------- #
114+
# Tcp:
115+
# immediately start serving:
116+
await StartTcpServer(context, identity=identity, address=("0.0.0.0", 5020), allow_reuse_address=True,
117+
defer_start=False)
118+
119+
# deferred start:
120+
# server = await StartTcpServer(context, identity=identity, address=("0.0.0.0", 5020),
121+
# allow_reuse_address=True, defer_start=True)
122+
#
123+
# asyncio.get_event_loop().call_later(20, lambda : server.serve_forever)
124+
# await server.serve_forever()
125+
126+
# TCP with different framer
127+
# StartTcpServer(context, identity=identity,
128+
# framer=ModbusRtuFramer, address=("0.0.0.0", 5020))
129+
130+
# Udp:
131+
# server = await StartUdpServer(context, identity=identity, address=("0.0.0.0", 5020),
132+
# allow_reuse_address=True, defer_start=True)
133+
# #
134+
# await server.serve_forever()
135+
136+
# !!! SERIAL SERVER NOT IMPLEMENTED !!!
137+
# Ascii:
138+
# StartSerialServer(context, identity=identity,
139+
# port='/dev/ttyp0', timeout=1)
140+
141+
# RTU:
142+
# StartSerialServer(context, framer=ModbusRtuFramer, identity=identity,
143+
# port='/dev/ttyp0', timeout=.005, baudrate=9600)
144+
145+
# Binary
146+
# StartSerialServer(context,
147+
# identity=identity,
148+
# framer=ModbusBinaryFramer,
149+
# port='/dev/ttyp0',
150+
# timeout=1)
151+
152+
153+
if __name__ == "__main__":
154+
asyncio.run(run_server())
155+

0 commit comments

Comments
 (0)