Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
fbbf69e
Rebase to dev3.7
dices Sep 28, 2018
b8c968c
Adding 3.7 to travis configuration
dices Sep 22, 2018
38f1dc1
Updated documentation to resolve warnings introduced with the longer …
dices Sep 23, 2018
e40c78d
Fixed reference to deprecated asynchronous
dices Sep 28, 2018
44668d9
Merge pull request #2 from dices/Py37
dices Sep 28, 2018
e0829bd
Adding gmp disable to fix pypy build issues
dices Sep 28, 2018
06627b8
Adding gmp disable to fix pypy build issues
dices Sep 28, 2018
e11bff7
Removing travis python 3.7 configuration
dices Oct 2, 2018
0fce5b5
Adding asserts for Payload Endianness
EricDuminil Oct 8, 2018
3838f5f
Fixing example of Payload. Same Endianness for builder and decoder.
EricDuminil Oct 8, 2018
826a76c
Merge pull request #350 from EricDuminil/master
dhoomakethu Oct 9, 2018
13adf0a
Fix Sql db slave context validate and get methods - #139
dhoomakethu Oct 9, 2018
cd1cb1c
Merge branch 'dev3.7' of https://github.com/riptideio/pymodbus into d…
dices Oct 10, 2018
05afbb0
Merge pull request #351 from riptideio/#139-SqlDb-Context
dhoomakethu Oct 15, 2018
d00a8cd
#353 - debugging, Add debug logs to check size of avaialble data in r…
dhoomakethu Oct 16, 2018
e85057a
#353 Provide an option to disable inter char timeouts
dhoomakethu Oct 17, 2018
c0a2359
#353 Bump version, update changelog
dhoomakethu Oct 18, 2018
aef3e0a
Merge pull request #355 from riptideio/#353-Error-Reading-Registers
dhoomakethu Oct 23, 2018
e09fed7
Merge pull request #346 from dices/dev3.7
dhoomakethu Oct 23, 2018
b3281fe
Merge pull request #362 from riptideio/dev3.7
dhoomakethu Jan 12, 2019
7e1c728
check self.socket (#354)
mpf82 Jan 14, 2019
d14318f
Fix typo (#378)
kimhanse Jan 26, 2019
9ff42d1
Pymodbus 2.2.0 (#375)
dhoomakethu Apr 18, 2019
9dcdca8
Fix docs (#407)
dhoomakethu Apr 19, 2019
c42d619
Merge branch 'master' into dev
dhoomakethu Apr 19, 2019
14af637
Remove pycrypto dep (#411)
tracernz Apr 22, 2019
13384e4
Fix --upgrade option in install dependencies (#413)
acanidio May 13, 2019
92b4428
Padding for odd sized responses (#425)
tcplomp Jul 25, 2019
ca74132
README update: REPL stands for Read Evaluate **Print** Loop (#426)
alecjohanson Jul 30, 2019
6a6ebde
Drop python 3.4 support (#440)
tracernz Sep 9, 2019
b6429fc
Re-enable travis python 3.7 builds (#441)
tracernz Sep 9, 2019
68932a3
Update __init__.py (#436)
hackerboygn Sep 9, 2019
c645605
Use SPDX identifier to specify the exact license type (#427)
yegorich Sep 9, 2019
e6da559
asyncio server implementation (#400)
memetb Sep 9, 2019
050b03c
Add option to repl allowing Modbus RTU framing on a TCP socket (#447)
Sekenre Sep 26, 2019
cc6e976
Fix asynci server test failures on python3.6 and below
Oct 7, 2019
507e8a0
Bump version to 2.2.0rc1, update six requirements and Changelog
Oct 7, 2019
fedea33
Support multiple Python versions to fix test error from PR #400 (#444)
starnight Oct 17, 2019
4bdf738
Add TLS feature for Modbus synchronous (#446)
starnight Oct 28, 2019
3fb83cc
Fix #461 - Udp client/server , Fix #401 - package license with source…
dhoomakethu Oct 29, 2019
b97659d
Fix examples, Merge #431
dhoomakethu Oct 29, 2019
632d300
#401 Move license to root folder from docs
dhoomakethu Oct 29, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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
  • Loading branch information
memetb authored and dhoomakethu committed Sep 9, 2019
commit e6da559e0fe98adb87ef7e03897b2ae817674f49
158 changes: 158 additions & 0 deletions examples/common/asyncio_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
#!/usr/bin/env python
"""
Pymodbus Asyncio Server Example
--------------------------------------------------------------------------

The asyncio server is implemented in pure python without any third
party libraries (unless you need to use the serial protocols which require
asyncio-pyserial). This is helpful in constrained or old environments where using
twisted is just not feasible. What follows is an example of its use:
"""
# --------------------------------------------------------------------------- #
# import the various server implementations
# --------------------------------------------------------------------------- #
from pymodbus.server.asyncio import StartTcpServer
from pymodbus.server.asyncio import StartUdpServer
from pymodbus.server.asyncio import StartSerialServer

from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSparseDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext

from pymodbus.transaction import ModbusRtuFramer, ModbusBinaryFramer
# --------------------------------------------------------------------------- #
# configure the service logging
# --------------------------------------------------------------------------- #
import logging
FORMAT = ('%(asctime)-15s %(threadName)-15s'
' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)


async def run_server():
# ----------------------------------------------------------------------- #
# initialize your data store
# ----------------------------------------------------------------------- #
# The datastores only respond to the addresses that they are initialized to
# Therefore, if you initialize a DataBlock to addresses of 0x00 to 0xFF, a
# request to 0x100 will respond with an invalid address exception. This is
# because many devices exhibit this kind of behavior (but not all)::
#
# block = ModbusSequentialDataBlock(0x00, [0]*0xff)
#
# Continuing, you can choose to use a sequential or a sparse DataBlock in
# your data context. The difference is that the sequential has no gaps in
# the data while the sparse can. Once again, there are devices that exhibit
# both forms of behavior::
#
# block = ModbusSparseDataBlock({0x00: 0, 0x05: 1})
# block = ModbusSequentialDataBlock(0x00, [0]*5)
#
# Alternately, you can use the factory methods to initialize the DataBlocks
# or simply do not pass them to have them initialized to 0x00 on the full
# address range::
#
# store = ModbusSlaveContext(di = ModbusSequentialDataBlock.create())
# store = ModbusSlaveContext()
#
# Finally, you are allowed to use the same DataBlock reference for every
# table or you may use a separate DataBlock for each table.
# This depends if you would like functions to be able to access and modify
# the same data or not::
#
# block = ModbusSequentialDataBlock(0x00, [0]*0xff)
# store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)
#
# The server then makes use of a server context that allows the server to
# respond with different slave contexts for different unit ids. By default
# it will return the same context for every unit id supplied (broadcast
# mode).
# However, this can be overloaded by setting the single flag to False and
# then supplying a dictionary of unit id to context mapping::
#
# slaves = {
# 0x01: ModbusSlaveContext(...),
# 0x02: ModbusSlaveContext(...),
# 0x03: ModbusSlaveContext(...),
# }
# context = ModbusServerContext(slaves=slaves, single=False)
#
# The slave context can also be initialized in zero_mode which means that a
# request to address(0-7) will map to the address (0-7). The default is
# False which is based on section 4.4 of the specification, so address(0-7)
# will map to (1-8)::
#
# store = ModbusSlaveContext(..., zero_mode=True)
# ----------------------------------------------------------------------- #
store = ModbusSlaveContext(
di=ModbusSequentialDataBlock(0, [17]*100),
co=ModbusSequentialDataBlock(0, [17]*100),
hr=ModbusSequentialDataBlock(0, [17]*100),
ir=ModbusSequentialDataBlock(0, [17]*100))

context = ModbusServerContext(slaves=store, single=True)

# ----------------------------------------------------------------------- #
# initialize the server information
# ----------------------------------------------------------------------- #
# If you don't set this or any fields, they are defaulted to empty strings.
# ----------------------------------------------------------------------- #
identity = ModbusDeviceIdentification()
identity.VendorName = 'Pymodbus'
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/riptideio/pymodbus/'
identity.ProductName = 'Pymodbus Server'
identity.ModelName = 'Pymodbus Server'
identity.MajorMinorRevision = '2.2.0'

# ----------------------------------------------------------------------- #
# run the server you want
# ----------------------------------------------------------------------- #
# Tcp:
# immediately start serving:
server = await StartTcpServer(context, identity=identity, address=("0.0.0.0", 5020),
allow_reuse_address=True)

# deferred start:
# server = await StartTcpServer(context, identity=identity, address=("0.0.0.0", 5020),
# allow_reuse_address=True, defer_start=True)

# asyncio.get_event_loop().call_later(20, lambda : server.)
# await server.serve_forever()




# TCP with different framer
# StartTcpServer(context, identity=identity,
# framer=ModbusRtuFramer, address=("0.0.0.0", 5020))

# Udp:
# server = await StartUdpServer(context, identity=identity, address=("0.0.0.0", 5020),
# allow_reuse_address=True, defer_start=True)
#
# await server.serve_forever()


# !!! SERIAL SERVER NOT IMPLEMENTED !!!
# Ascii:
# StartSerialServer(context, identity=identity,
# port='/dev/ttyp0', timeout=1)

# RTU:
# StartSerialServer(context, framer=ModbusRtuFramer, identity=identity,
# port='/dev/ttyp0', timeout=.005, baudrate=9600)

# Binary
# StartSerialServer(context,
# identity=identity,
# framer=ModbusBinaryFramer,
# port='/dev/ttyp0',
# timeout=1)


if __name__ == "__main__":
asyncio.run(run_server())

2 changes: 1 addition & 1 deletion pymodbus/client/sync.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import socket
import select
import serial
import time
import sys
from functools import partial
Expand Down Expand Up @@ -425,6 +424,7 @@ def __init__(self, method='ascii', **kwargs):
:param strict: Use Inter char timeout for baudrates <= 19200 (adhere
to modbus standards)
"""
import serial
self.method = method
self.socket = None
BaseModbusClient.__init__(self, self.__implementation(method, self),
Expand Down
Loading