Skip to content
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

Update use pyserial RS485 #2205

Closed
wants to merge 23 commits into from
Closed

Conversation

samskiter
Copy link

Fixes: #2204

@samskiter
Copy link
Author

Can't get this passing - it seems that serial_for_url is used by this library, but there's no way to use that to produce instances of pyserial's RS485 class. Perhaps the solution is to implement some kind of custom URL scheme for this purpose?

Copy link
Collaborator

@janiversen janiversen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems your fix breaks quite a number of tests, please fix.

@samskiter
Copy link
Author

Open to suggestions - I can't seem to fix it!

@janiversen
Copy link
Collaborator

I have no suggestions, the serial library is only used in serial transport and there are no other libraries being used.

serial_for_url is essential for pymodbus since it allows simulating serial communication on a socket, but it's strange if the rs485 do not supply it.

@samskiter
Copy link
Author

OK, I think this is actually a bit of an awkward solution, but ultimately the correct thing to do.

The purpose of using the RS485 class is to be able to configure RS485Settings, and without injecting those, I'll have to reach inside pymodbus and grab things I shouldn't to set rs485_mode on the sync_serial client. So I opted to allow these settings to be injected along with us in the commparams - there is precedent for params in there to be unused for some transports (e.g. the port parameter is not used if you have a serial commtype)

I hope this is an acceptable fix

@samskiter samskiter requested a review from janiversen May 31, 2024 13:04
Copy link
Collaborator

@janiversen janiversen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor details, the only bigger thing is your use (or not use) of comm_params.

We are in the process of preparing v3.7.0 so if you hurry this PR can be part of 3.7.0

@janiversen
Copy link
Collaborator

It is easiest to run locally "pytest --cov"

@samskiter samskiter requested a review from janiversen June 6, 2024 17:37
@@ -15,6 +15,7 @@

try:
import serial
from serial.rs485 import RS485Settings
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is already imported in the line above, do not import twice.

@@ -8,25 +8,36 @@

with contextlib.suppress(ImportError):
import serial
import serial.rs485
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is already imported in the line above.

@@ -58,6 +58,8 @@
from functools import partial
from typing import Any

from serial.rs485 import RS485Settings
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if serial is not installed ?? Please import as serial is imported in other places.

@@ -7,6 +7,7 @@

import pytest
import serial
from serial.rs485 import RS485Settings
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already imported in the line above, please do not import twice.

@janiversen
Copy link
Collaborator

We have for other reasons decided to make a v3.6.9 that will be done this weekend, so I need an updated PR from you if you want it included.

@janiversen
Copy link
Collaborator

Still working on this ?

@janiversen janiversen marked this pull request as draft July 20, 2024 06:49
@yawor
Copy link

yawor commented Jul 25, 2024

I have a personal project where I write a new software for already existing hardware with RS485 transceiver, but it is based on an AllWinner H3 SBC, where hardware flow control doesn't work very well, but I need to control RTS pin to control the transceiver's direction. So I really would like to have this feature merged, but (with all due respect to @samskiter) I don't think this is implemented properly.

SerialTransport adapts a non-asyncio serial.Serial class by adding async readers and writers to monitor serial port's file descriptor and they invoke callbacks to either read or write the data in a non-blocking fashion using normally blocking read and write methods. But RS485.write method adds additional, blocking delays (for example, it always flushes the port after each write), which should not be executed in the async writer's callbacks, because it's going to block the loop.

Also there's no guarantee that the async writer is going to call the callback only once per SerialTransport.write call as it's possible that the writer would split larger data into smaller chunks. In that case there would be multiple calls to RS485.write method for a single SerialTransport.write call, causing RTS to be toggled (potentially multiple times) in the middle of a single modbus operation, causing it to fail.

That's why the optional software RTS control should be implemented directly in the SerialTransport class, which is actually aware when the whole frame has been sent and RTS can be switched from TX to RX. It would be even better if it could just call program provided callbacks (either sync or async) before transmission starts and after it ends. That way a program could even use any available generic GPIO pin to control the transceiver direction, not just RTS pin.

@janiversen
Copy link
Collaborator

In general I agree with your arguments, we have over time had many problems with serial, a lot because it is no longer actively maintained.

We have been thinking of changing serial to another library, but never got time to actually do it.

I would however like to see a good RS485 integration! and e.g. enhac3 the transport layer to control RTS would also be welcomed.

So in short, and since this PR looks abandoned, I hope you will submit your ideas as a PR.

@janiversen
Copy link
Collaborator

I think RTS control can be implemented in the current serial transport, with an extra parameter to turn it on.

The best way would be to make a PR that implement it in serial transport with test, and a second that add the parameter to comm_params and the client/server api.

@samskiter
Copy link
Author

samskiter commented Jul 26, 2024 via email

@janiversen
Copy link
Collaborator

@samskiter good luck, please resolve the conflicts first and then have a close look at the comments from @yawor which I think have a lot of merit.

Ohh and do not forget the review comments I made.

Copy link

This PR is stale because it has been open 45 days with no activity. Remove stale label or comment or this will be closed in 10 days.

Copy link

This PR was closed because it has been stalled for 10 days with no activity.

@jameshilliard
Copy link
Contributor

But RS485.write method adds additional, blocking delays (for example, it always flushes the port after each write), which should not be executed in the async writer's callbacks, because it's going to block the loop.

So it appears pyserial also has some native rs485 support that AFAIU would avoid these issues, reworked this a bit to use that instead in #2460.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use pyserial RS485 - not serial_from_url
4 participants