-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add asyncio support #56
base: develop
Are you sure you want to change the base?
Add asyncio support #56
Conversation
Added a compatibility layer `sys_imports.py` which handles imports across different runtimes, and modified classes to use these imports.
Refactored pycopy-based code to match source repo style; requires adding unit tests and examples.
Thank you @GimmickNG for your PR 🎊 I need a deeper review and testing the next days but the first impression is very good 👍🏻
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've now had the time to review your changes, only minor things to be resolved
Thanks for the review. I'll make the changes required (and I also spotted some errors when I tried using the library, whose fixes I'll add here) in a week or so, when I should have more time available. |
I'm not sure why Github doesn't recognize that the
|
Hello. I'm happy that we are closer to have the I would like to say that I will happy to help on the tests with the serial version ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're almost there, very good implementation, love to see this live soon
Co-authored-by: Jones <[email protected]>
Changes `Modbus.process` to use `None` by default to avoid breaking changes Co-authored-by: Jones <[email protected]>
Revert `RTUServer` to `Serial`, add missing docstrings, shebangs and other metadata, and use named parameters in function calls. In `asynchronous` TCP and RTU implementations: moved `request` parameter for `send_exception_response` and `send_response` to end of function, and changed them to `Optional` for compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@beyonlo could you test the first release candidate of this lib with Async support? https://test.pypi.org/project/micropython-modbus/2.4.0rc39.dev56/ |
Hello @brainelectronics
Yes, of course I can do that. Are there some example to run the
I downloaded this version, but it seems not to have the pi@pi:~/Downloads/micropython-modbus-2.4.0rc39.dev56$ ls -la
total 32
drwxrwxr-x 4 pi pi 4096 mar 6 10:38 .
drwxr-xr-x 5 pi pi 20480 mar 6 10:38 ..
drwxrwxr-x 2 pi pi 4096 mar 6 10:38 micropython_modbus.egg-info
drwxrwxr-x 2 pi pi 4096 mar 6 10:46 umodbus
pi@pi:~/Downloads/micropython-modbus-2.4.0rc39.dev56$ cd umodbus/
pi@pi:~/Downloads/micropython-modbus-2.4.0rc39.dev56/umodbus$ ls -la
total 136
drwxrwxr-x 2 pi pi 4096 mar 6 10:46 .
drwxrwxr-x 4 pi pi 4096 mar 6 10:38 ..
-rw-r--r-- 1 pi pi 14741 mar 6 05:04 common.py
-rw-r--r-- 1 pi pi 6785 mar 6 05:04 const.py
-rw-r--r-- 1 pi pi 14778 mar 6 05:04 functions.py
-rw-r--r-- 1 pi pi 108 mar 6 05:04 __init__.py
-rw-r--r-- 1 pi pi 36148 mar 6 05:04 modbus.py
-rw-r--r-- 1 pi pi 17275 mar 6 05:04 serial.py
-rw-r--r-- 1 pi pi 1304 mar 6 05:04 sys_imports.py
-rw-r--r-- 1 pi pi 15704 mar 6 05:04 tcp.py
-rw-r--r-- 1 pi pi 2121 mar 6 05:04 typing.py
-rw-r--r-- 1 pi pi 140 mar 6 05:07 version.py
pi@pi:~/Downloads/micropython-modbus-2.4.0rc39.dev56/umodbus$ cat version.py
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__version_info__ = ("2", "4", "0")
__version__ = '.'.join(__version_info__) + '-rc39.dev56'
pi@pi:~/Downloads/micropython-modbus-2.4.0rc39.dev56/umodbus$ grep -i uasyncio *
pi@pi:~/Downloads/micropython-modbus-2.4.0rc39.dev56/umodbus$ Thank you! |
@beyonlo I am currently writing a few examples for the async clients and servers. However, I noticed that when writing the client and server examples for async RTU, some features in TCP were not present in RTU and had to be implemented manually (such as @brainelectronics I am making changes to make the async version more consistent with the sync one for the RTU implementation - namely, changing the regular |
@beyonlo best finding so far 😂 I've fixed the packaging code, let's try again with 2.4.0rc40.dev56 @GimmickNG could you please update the packages=['umodbus', 'umodbus/asynchronous'], Regarding backwards compability: As long as the following imports and the top level function names do not change in the sync part of the lib, I'm open to many changes as long as they are related to this PR of course from umodbus.serial import ModbusRTU
from umodbus.serial import Serial as ModbusRTUMaster
from umodbus.tcp import ModbusTCP
from umodbus.tcp import TCP as ModbusTCPMaster |
@GimmickNG Thanks for your effort to support Will be all features of this lib available/works on the |
Adds examples for async TCP and RTU clients and servers
Refactored the sync and async RTU classes to match the TCP counterparts. Instead of `Serial` being both a modbus RTU client *and* server, the server functionality has been split off into the `RTUServer` class, and `Serial` is now only the RTU client. `ModbusRTU` remains unaffected as its `_itf` is changed from `Serial` to `RTUServer`, but the user-facing API remains the same as they handle the same tasks as before.
Adds async package to the wheel via setup.py
@beyonlo Since the async version is based off/depends on the sync version, the two should be fairly similar (with the exception of Also, check async_examples.py for the async TCP/RTU examples. I haven't verified these though so there may be some errors, but I don't expect any initially. @brainelectronics I split off the server/slave functionality of |
@modbusrtus Sure, no worries! If you want to scale it across several slave/servers, then you could automate the callbacks by binding the function parameters in an inner function, like so:
Untested, but I believe it should work - it basically generates a callback each time |
@beyonlo I think Problem 1 is more related to the one that @modbusrtus had with the shared registers. The callback should be changed to call Both of these problems should theoretically be fixed automatically if/when the |
Hello @GimmickNG
Understood. I agree to create another PR just to add that Well, so we finish this PR to be merged! Thank you so much! |
@beyonlo I thought about it and decided to modify the The only downside is that the multi client examples won't have the regular callbacks working, since right now there can only be one callback at a time, and that's being used to synchronize the registers and coils across both slaves/servers. I could modify the sync callbacks to check if there's any existing callbacks and wrap those if needed, but that's going to introduce a lot more complexity for something that'll probably be reverted (hopefully soon) down the line. |
@GimmickNG Hello, sorry for the long time! Follow the tests with the new version: $ mpremote run multi_client_example.py
Waiting for WiFi connection...
Waiting for WiFi connection...
Waiting for WiFi connection...
Waiting for WiFi connection...
Connected to WiFi.
('192.168.238.177', '255.255.255.0', '192.168.238.111', '192.168.238.111')
MicroPython infos: (sysname='esp32', nodename='esp32', release='1.22.1', version='v1.22.1 on 2024-01-05', machine='Generic ESP32S3 module with ESP32S3')
Used micropthon-modbus version: 2.3.7
Using pins (37, 38) with UART ID 1
Traceback (most recent call last):
File "<stdin>", line 90, in <module>
TypeError: function missing required positional argument #1 Ps: I did just a fix in the import, because the $ diff multi_client_example.py /home/pi/Downloads/modbus/04.03.2024/pycopy-modbus-mpmodbus-compatibility/examples/multi_client_example.py
29c29
< from examples.common.register_definitions import register_definitions
---
> from examples.common.tcp_client_common import register_definitions
40d39
< ctrl_pin,
48d46
< ctrl_pin=ctrl_pin,
96c94
< ctrl_pin=15, # optional, control DE/RE
---
> # ctrl_pin=12, # optional, control DE/RE Thank you! |
@beyonlo Thanks for testing, and sorry for the delay! I've fixed the error in initializing the RTU server for the three scripts, and should hopefully work now. I don't think you need to add the |
Hello @GimmickNG
Unfortunatelly that +1 (
You are right about that. I just change Thank you! EDIT: Just to be clear with "does not works[*]": They does not show errors, just the Masters does not receive counter +1. The Masters receives always the same number. |
Hi @beyonlo, does the same issue occur with the TCP server example? Also, do you see any messages being called when the get register callback is called, or is the console empty (in which case the getter is probably not being called at all)? |
Hello @GimmickNG On the TCP works fine. On the console shows the called, but reply always the same number, not the number + 1. |
* revert changes to examples * remove multi_client_sync.py
@beyonlo Sorry for the huge delay. I'm not sure why the serial version isn't working, so rather than hold this pull request up any more I've decided to just revert it to the last known working version. Could you please test this and see if the revert has worked successfully? If so, this could be closed and the multi client sync could be handled later once shared register support is added. |
@GimmickNG Unfortunately the team that I was working with in this project changed the priority for another project, and I have no more hardware (485 transceivers to test). This does not mean that we will abandon the project, but I don't know when the lider team will give me time and prototypes again to work on this project. So, I was thinking to back to our last strategy/conversation to merge this PR and create another PR to fix other problems. This conversation happened in on Feb 12: What do you think? Thank you! |
@beyonlo Sounds good to me. I restored the files from commit 7ea5124 which was the version just before I made the changes to the multi client examples. So I think it should work since there were only formatting changes made between that version and the one you confirmed was working. In which case, @brainelectronics could this PR be merged, if there aren't any other comments? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's see what CI will report
umodbus/functions.py
Outdated
@@ -429,7 +430,7 @@ def float_to_bin(num: float) -> bin: | |||
:rtype: bin | |||
""" | |||
# no "zfill" available in MicroPython | |||
# return bin(struct.unpack('!I', struct.pack('!f', num))[0])[2:].zfill(32) | |||
# return bin(struct.struct.unpack('!I', struct.struct.pack('!f', num))[0])[2:].zfill(32) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume there is one struct
to much, although it's just a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I missed that part when I was adding the struct
module back to the imported methoids pack
and unpack
.
I'll try to finally review and test on my side by the end of this week, Jan 2023, ... this change has to be great :D |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So manually running the CI reported no error 🥳
@GimmickNG could you do me one last favour? Please update the changelog.md
and package.json
a very last time. The version shall become 3.0.0
as some classes got renamed
umodbus/common.py
Outdated
@@ -81,6 +80,7 @@ def send_response(self, | |||
:param signed: Indicates if signed values are used | |||
:type signed: bool | |||
""" | |||
print("sending sync response...", type(self).__name__, "->", type(self._itf).__name__) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is either a logging output or can be removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this was mainly for debugging. Removed, thanks!
@beyonlo could you test the final release candidate of this lib with Async support? https://test.pypi.org/project/micropython-modbus/2.4.0rc83.dev56/ |
Hello @GimmickNG Unfortunately the team that I was working with in this project changed the priority for another project, and I have no more hardware (485 transceivers to test), kits, and so on. This does not mean that we will abandon the project, but I don't know when the lider team will give me time and prototypes again to work on this project. Until now I did all tests possible in this project, but from now would be great if we found another person to help us on tests. I'm sorry! |
@brainelectronics unfortunately it is not currently possible for @beyonlo to test due to circumstances outside his control. However, I expect the async RTU and TCP should both work as it was restored to the last known working state a while ago. |
Hello @GimmickNG Sorry, the message above I replied to you instead to @brainelectronics ! @GimmickNG yes, until this point of PR I already test everything - in many details, so, if the merge was OK, I think that will have no problems in my view. Of course, would be great test again, now in the official lib, but the PR was tested much for me. |
Hello @brainelectronics Would be great if this PR can be merged. We had a hard work (mostly @GimmickNG), so It would be bad for the library if this PR is forgotten. |
Hello, Can you tell me how to test this PR? Have you made any examples? I'd like to participate (at my level) Thank you for your work. |
With reference to my comment in #5, I've added asyncio support for TCP and limited support for Serial RTU. Right now, async serial support is TBD but I've left the class in just in case anyone else wants to try modifying it themselves. To avoid code duplication, I've based the async classes off their synchronous equivalents, and only modified parts when I couldn't cleanly link the two.
I haven't tested the results yet, but I expect it to work for the most part. So I guess until later, this is still very much as "use at your own risk" situation since it could be rather buggy now.