-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
[modbus] Modbus transport API simplification #7994
Conversation
Prebuilt jars for commit 9a65a4a (June 23, 2020) |
Travis tests have failedHey @ssalonen, |
1 similar comment
Travis tests have failedHey @ssalonen, |
fce24c0
to
e78cf01
Compare
Travis tests have failedHey @ssalonen, |
1 similar comment
Travis tests have failedHey @ssalonen, |
Travis tests were successfulHey @ssalonen, |
...ain/java/org/openhab/binding/modbus/internal/handler/AbstractModbusEndpointThingHandler.java
Outdated
Show resolved
Hide resolved
...io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/AsyncModbusReadResult.java
Outdated
Show resolved
Hide resolved
...ansport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusReadRequestBlueprint.java
Show resolved
Hide resolved
...b.io.transport.modbus/src/main/java/org/openhab/io/transport/modbus/ModbusRegisterArray.java
Show resolved
Hide resolved
...ansport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusManagerImpl.java
Outdated
Show resolved
Hide resolved
...ansport.modbus/src/main/java/org/openhab/io/transport/modbus/internal/ModbusManagerImpl.java
Outdated
Show resolved
Hide resolved
...modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusDataThingHandler.java
Outdated
Show resolved
Hide resolved
...inding.modbus/src/main/java/org/openhab/binding/modbus/handler/ModbusPollerThingHandler.java
Show resolved
Hide resolved
...main/java/org/openhab/binding/modbus/sunspec/internal/discovery/SunspecDiscoveryProcess.java
Outdated
Show resolved
Hide resolved
...main/java/org/openhab/binding/modbus/sunspec/internal/discovery/SunspecDiscoveryProcess.java
Outdated
Show resolved
Hide resolved
I think error handling is mandatory. Why not adding a second functional interface to
|
@fwolter very valid suggestion! With @mrbig we tried to model other similar APIS which bundle errors and valid results into same object We played with several different API designs but to be honest, separating error from the successful result was not one of them. By separating the error case the API consumer can avoid an if statement. On the other hand, bundling error case to the same result object makes it clear when the operation has ended (either successfully or with error). Are there any other upsides/downsides? Either way will certainly work. Any thoughts @mrbig ? I am not too keen on changing this if the gained benefit is small - it is somewhat large change considering the large footprint of the tests. |
Handling result and exception paths separately reflects OOP paradigm. You don't need the casting and the I can't follow your argument. not being clear when the operation finished. You could specify either the error handler or the result handler is invoked, when the operation finished. |
@fwolter I like your thinking. I think it's especially valuable that you have to handle the errors and decide what to do with them. |
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
1b4fbf9
to
735d9d6
Compare
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
@mrbig (huge thanks! 👏 ) & me worked on this more and now errors are propagated via their own callback. We also use Optionals to wrap the data in callbacks New review welcome! |
started); | ||
try { | ||
executeOperation(task, false, pollOperation); | ||
} catch (RuntimeException e) { |
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.
Cherry-picked 5bde9d6 during rebase in this commit.
Travis tests were successfulHey @ssalonen, |
1 similar comment
Travis tests were successfulHey @ssalonen, |
...modbus/src/main/java/org/openhab/binding/modbus/internal/handler/ModbusDataThingHandler.java
Outdated
Show resolved
Hide resolved
...inding.modbus/src/main/java/org/openhab/binding/modbus/handler/ModbusPollerThingHandler.java
Outdated
Show resolved
Hide resolved
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Signed-off-by: Sami Salonen <ssalonen@gmail.com>
Travis tests were successfulHey @ssalonen, |
* [modbus] connection closing behaviour finetuned The binding closes TCP/serial connections connections as per user configuration. It is either - every time, immediately after a transaction (reconnectAfterMillis=0) - *after* a read/write transaction, if the connection has been open "too long" (configurable with reconnectAfterMillis) We have an obvious downside to this simple logic -- the connection can remain open "indefinitely" if there are no transactions occurring. With Modbus we are quite often dealing with PLCs and other embedded systems with limited resources, and "reserving" the connection is not always something we want. Previously (2.5.x branch) connections were also closed when - a regular poll task was unregistered (i.e. we stop reading regularly from a modbus server ("slave"). Since most users have regular polling in place, so this ensured that connections do get closed. In this commit, the behaviour is adjusted such that connections are closed when last communication interface pointing to the server/serial port (i.e. "endpoint") is close()'d. With modbus binding this basically means when the tcp or serial thing is removed / disabled, the connections is closed/freed, but only if it is the last thing pointing to that server or serial port. Since modbus.sunspec binding reuses modbus serial & tcp endpoint things, the same note applies for modbus.sunspec binding. This is change in functional behaviour but in a way is logical. We can further introduce to have "delayed"/"deferred"/"debounce" connection closing connections as per the setting reconnectAfterMillis even in situations where communication interface is still open. * [modbus] Check and disconnect idle connections without transactions * [modbus] mvn spotless:apply * [modbubs] Fixed log message * [modbus] Race condition fix The CountDownLatch was used as a guard (latch.await) in many tests to wait for callbacks to be called before proceeding with assertions. Since the latch was countDown() beginning of the callback, we introduced a race condition with the subsequent assertions and updating the other counters used in the subsequent assertions. This commit updates the CountDownLatch as the last step of the callback, resolving the race condition. * [modbus] small test fix * [modbus] readcallback changed to nonnull * [modbus] Refactored ModbusCommunicationInterface to have seperate callback for result and failure However I had to dig deep to reach all the affected parts. Also there is a new callback, and a new "result" type to communicate the failures. * [modbus] SmokeTest refactored to new api * [modbus] Modbus bundle refactored to use the new api * [modbus][sunspec] refactored sunspec bundle to use the new modbus API * [modbus] refactor modbus tests to use the new api * [modbus] Removed ModbusWriteCallback interface from ModbusDataThingHandler Also reset ModbusDataThingHandler testWriteHandling generic to it's original form * [modbus] ModbusDataThingHandler does not implement ModbusReadCallback anymore Instead it has a public onReadResult method. ModbusPollerThingHandler changed to work with ModbusDataThingHandler children. * [modbus] Fixed caching in ModbusPollerThingHandler * [modbus] read modbus data as Optionals * [modbus] toString for PollResult * [modbus] fixed confusing variable name * [modbus] Disallow null callbacks * [modbus] mvn spotless:apply * [modbus] Removing Nullable decorations * [modbus] submitOneTimeWrite simplification * [modbus] Less verbose logging * [modbus] submitOneTimePoll simplification * [modbus] Less verbose logging * [modbus] Many null warnings removed * [modbus] Fix: no need for a @nonnull annotation because it is default * [modbus] Removing unneeded Nullable, using final in immutables * [modbus] Explicit functional interface * [modbus] @nullable and @NonNullByDefault aligned with coding conventions * [modbus] Collections.emptyMap instead of allocating new map every time. Signed-off-by: Sami Salonen <ssalonen@gmail.com> Co-authored-by: Nagy Attila Gábor <mrbig@sneaker.hu>
* [modbus] connection closing behaviour finetuned The binding closes TCP/serial connections connections as per user configuration. It is either - every time, immediately after a transaction (reconnectAfterMillis=0) - *after* a read/write transaction, if the connection has been open "too long" (configurable with reconnectAfterMillis) We have an obvious downside to this simple logic -- the connection can remain open "indefinitely" if there are no transactions occurring. With Modbus we are quite often dealing with PLCs and other embedded systems with limited resources, and "reserving" the connection is not always something we want. Previously (2.5.x branch) connections were also closed when - a regular poll task was unregistered (i.e. we stop reading regularly from a modbus server ("slave"). Since most users have regular polling in place, so this ensured that connections do get closed. In this commit, the behaviour is adjusted such that connections are closed when last communication interface pointing to the server/serial port (i.e. "endpoint") is close()'d. With modbus binding this basically means when the tcp or serial thing is removed / disabled, the connections is closed/freed, but only if it is the last thing pointing to that server or serial port. Since modbus.sunspec binding reuses modbus serial & tcp endpoint things, the same note applies for modbus.sunspec binding. This is change in functional behaviour but in a way is logical. We can further introduce to have "delayed"/"deferred"/"debounce" connection closing connections as per the setting reconnectAfterMillis even in situations where communication interface is still open. * [modbus] Check and disconnect idle connections without transactions * [modbus] mvn spotless:apply * [modbubs] Fixed log message * [modbus] Race condition fix The CountDownLatch was used as a guard (latch.await) in many tests to wait for callbacks to be called before proceeding with assertions. Since the latch was countDown() beginning of the callback, we introduced a race condition with the subsequent assertions and updating the other counters used in the subsequent assertions. This commit updates the CountDownLatch as the last step of the callback, resolving the race condition. * [modbus] small test fix * [modbus] readcallback changed to nonnull * [modbus] Refactored ModbusCommunicationInterface to have seperate callback for result and failure However I had to dig deep to reach all the affected parts. Also there is a new callback, and a new "result" type to communicate the failures. * [modbus] SmokeTest refactored to new api * [modbus] Modbus bundle refactored to use the new api * [modbus][sunspec] refactored sunspec bundle to use the new modbus API * [modbus] refactor modbus tests to use the new api * [modbus] Removed ModbusWriteCallback interface from ModbusDataThingHandler Also reset ModbusDataThingHandler testWriteHandling generic to it's original form * [modbus] ModbusDataThingHandler does not implement ModbusReadCallback anymore Instead it has a public onReadResult method. ModbusPollerThingHandler changed to work with ModbusDataThingHandler children. * [modbus] Fixed caching in ModbusPollerThingHandler * [modbus] read modbus data as Optionals * [modbus] toString for PollResult * [modbus] fixed confusing variable name * [modbus] Disallow null callbacks * [modbus] mvn spotless:apply * [modbus] Removing Nullable decorations * [modbus] submitOneTimeWrite simplification * [modbus] Less verbose logging * [modbus] submitOneTimePoll simplification * [modbus] Less verbose logging * [modbus] Many null warnings removed * [modbus] Fix: no need for a @nonnull annotation because it is default * [modbus] Removing unneeded Nullable, using final in immutables * [modbus] Explicit functional interface * [modbus] @nullable and @NonNullByDefault aligned with coding conventions * [modbus] Collections.emptyMap instead of allocating new map every time. Signed-off-by: Sami Salonen <ssalonen@gmail.com> Co-authored-by: Nagy Attila Gábor <mrbig@sneaker.hu> Signed-off-by: CSchlipp <christian@schlipp.de>
* [modbus] connection closing behaviour finetuned The binding closes TCP/serial connections connections as per user configuration. It is either - every time, immediately after a transaction (reconnectAfterMillis=0) - *after* a read/write transaction, if the connection has been open "too long" (configurable with reconnectAfterMillis) We have an obvious downside to this simple logic -- the connection can remain open "indefinitely" if there are no transactions occurring. With Modbus we are quite often dealing with PLCs and other embedded systems with limited resources, and "reserving" the connection is not always something we want. Previously (2.5.x branch) connections were also closed when - a regular poll task was unregistered (i.e. we stop reading regularly from a modbus server ("slave"). Since most users have regular polling in place, so this ensured that connections do get closed. In this commit, the behaviour is adjusted such that connections are closed when last communication interface pointing to the server/serial port (i.e. "endpoint") is close()'d. With modbus binding this basically means when the tcp or serial thing is removed / disabled, the connections is closed/freed, but only if it is the last thing pointing to that server or serial port. Since modbus.sunspec binding reuses modbus serial & tcp endpoint things, the same note applies for modbus.sunspec binding. This is change in functional behaviour but in a way is logical. We can further introduce to have "delayed"/"deferred"/"debounce" connection closing connections as per the setting reconnectAfterMillis even in situations where communication interface is still open. * [modbus] Check and disconnect idle connections without transactions * [modbus] mvn spotless:apply * [modbubs] Fixed log message * [modbus] Race condition fix The CountDownLatch was used as a guard (latch.await) in many tests to wait for callbacks to be called before proceeding with assertions. Since the latch was countDown() beginning of the callback, we introduced a race condition with the subsequent assertions and updating the other counters used in the subsequent assertions. This commit updates the CountDownLatch as the last step of the callback, resolving the race condition. * [modbus] small test fix * [modbus] readcallback changed to nonnull * [modbus] Refactored ModbusCommunicationInterface to have seperate callback for result and failure However I had to dig deep to reach all the affected parts. Also there is a new callback, and a new "result" type to communicate the failures. * [modbus] SmokeTest refactored to new api * [modbus] Modbus bundle refactored to use the new api * [modbus][sunspec] refactored sunspec bundle to use the new modbus API * [modbus] refactor modbus tests to use the new api * [modbus] Removed ModbusWriteCallback interface from ModbusDataThingHandler Also reset ModbusDataThingHandler testWriteHandling generic to it's original form * [modbus] ModbusDataThingHandler does not implement ModbusReadCallback anymore Instead it has a public onReadResult method. ModbusPollerThingHandler changed to work with ModbusDataThingHandler children. * [modbus] Fixed caching in ModbusPollerThingHandler * [modbus] read modbus data as Optionals * [modbus] toString for PollResult * [modbus] fixed confusing variable name * [modbus] Disallow null callbacks * [modbus] mvn spotless:apply * [modbus] Removing Nullable decorations * [modbus] submitOneTimeWrite simplification * [modbus] Less verbose logging * [modbus] submitOneTimePoll simplification * [modbus] Less verbose logging * [modbus] Many null warnings removed * [modbus] Fix: no need for a @nonnull annotation because it is default * [modbus] Removing unneeded Nullable, using final in immutables * [modbus] Explicit functional interface * [modbus] @nullable and @NonNullByDefault aligned with coding conventions * [modbus] Collections.emptyMap instead of allocating new map every time. Signed-off-by: Sami Salonen <ssalonen@gmail.com> Co-authored-by: Nagy Attila Gábor <mrbig@sneaker.hu> Signed-off-by: MPH80 <michael@hazelden.me>
* [modbus] connection closing behaviour finetuned The binding closes TCP/serial connections connections as per user configuration. It is either - every time, immediately after a transaction (reconnectAfterMillis=0) - *after* a read/write transaction, if the connection has been open "too long" (configurable with reconnectAfterMillis) We have an obvious downside to this simple logic -- the connection can remain open "indefinitely" if there are no transactions occurring. With Modbus we are quite often dealing with PLCs and other embedded systems with limited resources, and "reserving" the connection is not always something we want. Previously (2.5.x branch) connections were also closed when - a regular poll task was unregistered (i.e. we stop reading regularly from a modbus server ("slave"). Since most users have regular polling in place, so this ensured that connections do get closed. In this commit, the behaviour is adjusted such that connections are closed when last communication interface pointing to the server/serial port (i.e. "endpoint") is close()'d. With modbus binding this basically means when the tcp or serial thing is removed / disabled, the connections is closed/freed, but only if it is the last thing pointing to that server or serial port. Since modbus.sunspec binding reuses modbus serial & tcp endpoint things, the same note applies for modbus.sunspec binding. This is change in functional behaviour but in a way is logical. We can further introduce to have "delayed"/"deferred"/"debounce" connection closing connections as per the setting reconnectAfterMillis even in situations where communication interface is still open. * [modbus] Check and disconnect idle connections without transactions * [modbus] mvn spotless:apply * [modbubs] Fixed log message * [modbus] Race condition fix The CountDownLatch was used as a guard (latch.await) in many tests to wait for callbacks to be called before proceeding with assertions. Since the latch was countDown() beginning of the callback, we introduced a race condition with the subsequent assertions and updating the other counters used in the subsequent assertions. This commit updates the CountDownLatch as the last step of the callback, resolving the race condition. * [modbus] small test fix * [modbus] readcallback changed to nonnull * [modbus] Refactored ModbusCommunicationInterface to have seperate callback for result and failure However I had to dig deep to reach all the affected parts. Also there is a new callback, and a new "result" type to communicate the failures. * [modbus] SmokeTest refactored to new api * [modbus] Modbus bundle refactored to use the new api * [modbus][sunspec] refactored sunspec bundle to use the new modbus API * [modbus] refactor modbus tests to use the new api * [modbus] Removed ModbusWriteCallback interface from ModbusDataThingHandler Also reset ModbusDataThingHandler testWriteHandling generic to it's original form * [modbus] ModbusDataThingHandler does not implement ModbusReadCallback anymore Instead it has a public onReadResult method. ModbusPollerThingHandler changed to work with ModbusDataThingHandler children. * [modbus] Fixed caching in ModbusPollerThingHandler * [modbus] read modbus data as Optionals * [modbus] toString for PollResult * [modbus] fixed confusing variable name * [modbus] Disallow null callbacks * [modbus] mvn spotless:apply * [modbus] Removing Nullable decorations * [modbus] submitOneTimeWrite simplification * [modbus] Less verbose logging * [modbus] submitOneTimePoll simplification * [modbus] Less verbose logging * [modbus] Many null warnings removed * [modbus] Fix: no need for a @nonnull annotation because it is default * [modbus] Removing unneeded Nullable, using final in immutables * [modbus] Explicit functional interface * [modbus] @nullable and @NonNullByDefault aligned with coding conventions * [modbus] Collections.emptyMap instead of allocating new map every time. Signed-off-by: Sami Salonen <ssalonen@gmail.com> Co-authored-by: Nagy Attila Gábor <mrbig@sneaker.hu>
* [modbus] connection closing behaviour finetuned The binding closes TCP/serial connections connections as per user configuration. It is either - every time, immediately after a transaction (reconnectAfterMillis=0) - *after* a read/write transaction, if the connection has been open "too long" (configurable with reconnectAfterMillis) We have an obvious downside to this simple logic -- the connection can remain open "indefinitely" if there are no transactions occurring. With Modbus we are quite often dealing with PLCs and other embedded systems with limited resources, and "reserving" the connection is not always something we want. Previously (2.5.x branch) connections were also closed when - a regular poll task was unregistered (i.e. we stop reading regularly from a modbus server ("slave"). Since most users have regular polling in place, so this ensured that connections do get closed. In this commit, the behaviour is adjusted such that connections are closed when last communication interface pointing to the server/serial port (i.e. "endpoint") is close()'d. With modbus binding this basically means when the tcp or serial thing is removed / disabled, the connections is closed/freed, but only if it is the last thing pointing to that server or serial port. Since modbus.sunspec binding reuses modbus serial & tcp endpoint things, the same note applies for modbus.sunspec binding. This is change in functional behaviour but in a way is logical. We can further introduce to have "delayed"/"deferred"/"debounce" connection closing connections as per the setting reconnectAfterMillis even in situations where communication interface is still open. * [modbus] Check and disconnect idle connections without transactions * [modbus] mvn spotless:apply * [modbubs] Fixed log message * [modbus] Race condition fix The CountDownLatch was used as a guard (latch.await) in many tests to wait for callbacks to be called before proceeding with assertions. Since the latch was countDown() beginning of the callback, we introduced a race condition with the subsequent assertions and updating the other counters used in the subsequent assertions. This commit updates the CountDownLatch as the last step of the callback, resolving the race condition. * [modbus] small test fix * [modbus] readcallback changed to nonnull * [modbus] Refactored ModbusCommunicationInterface to have seperate callback for result and failure However I had to dig deep to reach all the affected parts. Also there is a new callback, and a new "result" type to communicate the failures. * [modbus] SmokeTest refactored to new api * [modbus] Modbus bundle refactored to use the new api * [modbus][sunspec] refactored sunspec bundle to use the new modbus API * [modbus] refactor modbus tests to use the new api * [modbus] Removed ModbusWriteCallback interface from ModbusDataThingHandler Also reset ModbusDataThingHandler testWriteHandling generic to it's original form * [modbus] ModbusDataThingHandler does not implement ModbusReadCallback anymore Instead it has a public onReadResult method. ModbusPollerThingHandler changed to work with ModbusDataThingHandler children. * [modbus] Fixed caching in ModbusPollerThingHandler * [modbus] read modbus data as Optionals * [modbus] toString for PollResult * [modbus] fixed confusing variable name * [modbus] Disallow null callbacks * [modbus] mvn spotless:apply * [modbus] Removing Nullable decorations * [modbus] submitOneTimeWrite simplification * [modbus] Less verbose logging * [modbus] submitOneTimePoll simplification * [modbus] Less verbose logging * [modbus] Many null warnings removed * [modbus] Fix: no need for a @nonnull annotation because it is default * [modbus] Removing unneeded Nullable, using final in immutables * [modbus] Explicit functional interface * [modbus] @nullable and @NonNullByDefault aligned with coding conventions * [modbus] Collections.emptyMap instead of allocating new map every time. Signed-off-by: Sami Salonen <ssalonen@gmail.com> Co-authored-by: Nagy Attila Gábor <mrbig@sneaker.hu>
* [modbus] connection closing behaviour finetuned The binding closes TCP/serial connections connections as per user configuration. It is either - every time, immediately after a transaction (reconnectAfterMillis=0) - *after* a read/write transaction, if the connection has been open "too long" (configurable with reconnectAfterMillis) We have an obvious downside to this simple logic -- the connection can remain open "indefinitely" if there are no transactions occurring. With Modbus we are quite often dealing with PLCs and other embedded systems with limited resources, and "reserving" the connection is not always something we want. Previously (2.5.x branch) connections were also closed when - a regular poll task was unregistered (i.e. we stop reading regularly from a modbus server ("slave"). Since most users have regular polling in place, so this ensured that connections do get closed. In this commit, the behaviour is adjusted such that connections are closed when last communication interface pointing to the server/serial port (i.e. "endpoint") is close()'d. With modbus binding this basically means when the tcp or serial thing is removed / disabled, the connections is closed/freed, but only if it is the last thing pointing to that server or serial port. Since modbus.sunspec binding reuses modbus serial & tcp endpoint things, the same note applies for modbus.sunspec binding. This is change in functional behaviour but in a way is logical. We can further introduce to have "delayed"/"deferred"/"debounce" connection closing connections as per the setting reconnectAfterMillis even in situations where communication interface is still open. * [modbus] Check and disconnect idle connections without transactions * [modbus] mvn spotless:apply * [modbubs] Fixed log message * [modbus] Race condition fix The CountDownLatch was used as a guard (latch.await) in many tests to wait for callbacks to be called before proceeding with assertions. Since the latch was countDown() beginning of the callback, we introduced a race condition with the subsequent assertions and updating the other counters used in the subsequent assertions. This commit updates the CountDownLatch as the last step of the callback, resolving the race condition. * [modbus] small test fix * [modbus] readcallback changed to nonnull * [modbus] Refactored ModbusCommunicationInterface to have seperate callback for result and failure However I had to dig deep to reach all the affected parts. Also there is a new callback, and a new "result" type to communicate the failures. * [modbus] SmokeTest refactored to new api * [modbus] Modbus bundle refactored to use the new api * [modbus][sunspec] refactored sunspec bundle to use the new modbus API * [modbus] refactor modbus tests to use the new api * [modbus] Removed ModbusWriteCallback interface from ModbusDataThingHandler Also reset ModbusDataThingHandler testWriteHandling generic to it's original form * [modbus] ModbusDataThingHandler does not implement ModbusReadCallback anymore Instead it has a public onReadResult method. ModbusPollerThingHandler changed to work with ModbusDataThingHandler children. * [modbus] Fixed caching in ModbusPollerThingHandler * [modbus] read modbus data as Optionals * [modbus] toString for PollResult * [modbus] fixed confusing variable name * [modbus] Disallow null callbacks * [modbus] mvn spotless:apply * [modbus] Removing Nullable decorations * [modbus] submitOneTimeWrite simplification * [modbus] Less verbose logging * [modbus] submitOneTimePoll simplification * [modbus] Less verbose logging * [modbus] Many null warnings removed * [modbus] Fix: no need for a @nonnull annotation because it is default * [modbus] Removing unneeded Nullable, using final in immutables * [modbus] Explicit functional interface * [modbus] @nullable and @NonNullByDefault aligned with coding conventions * [modbus] Collections.emptyMap instead of allocating new map every time. Signed-off-by: Sami Salonen <ssalonen@gmail.com> Co-authored-by: Nagy Attila Gábor <mrbig@sneaker.hu>
* [modbus] connection closing behaviour finetuned The binding closes TCP/serial connections connections as per user configuration. It is either - every time, immediately after a transaction (reconnectAfterMillis=0) - *after* a read/write transaction, if the connection has been open "too long" (configurable with reconnectAfterMillis) We have an obvious downside to this simple logic -- the connection can remain open "indefinitely" if there are no transactions occurring. With Modbus we are quite often dealing with PLCs and other embedded systems with limited resources, and "reserving" the connection is not always something we want. Previously (2.5.x branch) connections were also closed when - a regular poll task was unregistered (i.e. we stop reading regularly from a modbus server ("slave"). Since most users have regular polling in place, so this ensured that connections do get closed. In this commit, the behaviour is adjusted such that connections are closed when last communication interface pointing to the server/serial port (i.e. "endpoint") is close()'d. With modbus binding this basically means when the tcp or serial thing is removed / disabled, the connections is closed/freed, but only if it is the last thing pointing to that server or serial port. Since modbus.sunspec binding reuses modbus serial & tcp endpoint things, the same note applies for modbus.sunspec binding. This is change in functional behaviour but in a way is logical. We can further introduce to have "delayed"/"deferred"/"debounce" connection closing connections as per the setting reconnectAfterMillis even in situations where communication interface is still open. * [modbus] Check and disconnect idle connections without transactions * [modbus] mvn spotless:apply * [modbubs] Fixed log message * [modbus] Race condition fix The CountDownLatch was used as a guard (latch.await) in many tests to wait for callbacks to be called before proceeding with assertions. Since the latch was countDown() beginning of the callback, we introduced a race condition with the subsequent assertions and updating the other counters used in the subsequent assertions. This commit updates the CountDownLatch as the last step of the callback, resolving the race condition. * [modbus] small test fix * [modbus] readcallback changed to nonnull * [modbus] Refactored ModbusCommunicationInterface to have seperate callback for result and failure However I had to dig deep to reach all the affected parts. Also there is a new callback, and a new "result" type to communicate the failures. * [modbus] SmokeTest refactored to new api * [modbus] Modbus bundle refactored to use the new api * [modbus][sunspec] refactored sunspec bundle to use the new modbus API * [modbus] refactor modbus tests to use the new api * [modbus] Removed ModbusWriteCallback interface from ModbusDataThingHandler Also reset ModbusDataThingHandler testWriteHandling generic to it's original form * [modbus] ModbusDataThingHandler does not implement ModbusReadCallback anymore Instead it has a public onReadResult method. ModbusPollerThingHandler changed to work with ModbusDataThingHandler children. * [modbus] Fixed caching in ModbusPollerThingHandler * [modbus] read modbus data as Optionals * [modbus] toString for PollResult * [modbus] fixed confusing variable name * [modbus] Disallow null callbacks * [modbus] mvn spotless:apply * [modbus] Removing Nullable decorations * [modbus] submitOneTimeWrite simplification * [modbus] Less verbose logging * [modbus] submitOneTimePoll simplification * [modbus] Less verbose logging * [modbus] Many null warnings removed * [modbus] Fix: no need for a @nonnull annotation because it is default * [modbus] Removing unneeded Nullable, using final in immutables * [modbus] Explicit functional interface * [modbus] @nullable and @NonNullByDefault aligned with coding conventions * [modbus] Collections.emptyMap instead of allocating new map every time. Signed-off-by: Sami Salonen <ssalonen@gmail.com> Co-authored-by: Nagy Attila Gábor <mrbig@sneaker.hu>
* [modbus] connection closing behaviour finetuned The binding closes TCP/serial connections connections as per user configuration. It is either - every time, immediately after a transaction (reconnectAfterMillis=0) - *after* a read/write transaction, if the connection has been open "too long" (configurable with reconnectAfterMillis) We have an obvious downside to this simple logic -- the connection can remain open "indefinitely" if there are no transactions occurring. With Modbus we are quite often dealing with PLCs and other embedded systems with limited resources, and "reserving" the connection is not always something we want. Previously (2.5.x branch) connections were also closed when - a regular poll task was unregistered (i.e. we stop reading regularly from a modbus server ("slave"). Since most users have regular polling in place, so this ensured that connections do get closed. In this commit, the behaviour is adjusted such that connections are closed when last communication interface pointing to the server/serial port (i.e. "endpoint") is close()'d. With modbus binding this basically means when the tcp or serial thing is removed / disabled, the connections is closed/freed, but only if it is the last thing pointing to that server or serial port. Since modbus.sunspec binding reuses modbus serial & tcp endpoint things, the same note applies for modbus.sunspec binding. This is change in functional behaviour but in a way is logical. We can further introduce to have "delayed"/"deferred"/"debounce" connection closing connections as per the setting reconnectAfterMillis even in situations where communication interface is still open. * [modbus] Check and disconnect idle connections without transactions * [modbus] mvn spotless:apply * [modbubs] Fixed log message * [modbus] Race condition fix The CountDownLatch was used as a guard (latch.await) in many tests to wait for callbacks to be called before proceeding with assertions. Since the latch was countDown() beginning of the callback, we introduced a race condition with the subsequent assertions and updating the other counters used in the subsequent assertions. This commit updates the CountDownLatch as the last step of the callback, resolving the race condition. * [modbus] small test fix * [modbus] readcallback changed to nonnull * [modbus] Refactored ModbusCommunicationInterface to have seperate callback for result and failure However I had to dig deep to reach all the affected parts. Also there is a new callback, and a new "result" type to communicate the failures. * [modbus] SmokeTest refactored to new api * [modbus] Modbus bundle refactored to use the new api * [modbus][sunspec] refactored sunspec bundle to use the new modbus API * [modbus] refactor modbus tests to use the new api * [modbus] Removed ModbusWriteCallback interface from ModbusDataThingHandler Also reset ModbusDataThingHandler testWriteHandling generic to it's original form * [modbus] ModbusDataThingHandler does not implement ModbusReadCallback anymore Instead it has a public onReadResult method. ModbusPollerThingHandler changed to work with ModbusDataThingHandler children. * [modbus] Fixed caching in ModbusPollerThingHandler * [modbus] read modbus data as Optionals * [modbus] toString for PollResult * [modbus] fixed confusing variable name * [modbus] Disallow null callbacks * [modbus] mvn spotless:apply * [modbus] Removing Nullable decorations * [modbus] submitOneTimeWrite simplification * [modbus] Less verbose logging * [modbus] submitOneTimePoll simplification * [modbus] Less verbose logging * [modbus] Many null warnings removed * [modbus] Fix: no need for a @nonnull annotation because it is default * [modbus] Removing unneeded Nullable, using final in immutables * [modbus] Explicit functional interface * [modbus] @nullable and @NonNullByDefault aligned with coding conventions * [modbus] Collections.emptyMap instead of allocating new map every time. Signed-off-by: Sami Salonen <ssalonen@gmail.com> Co-authored-by: Nagy Attila Gábor <mrbig@sneaker.hu> Signed-off-by: Daan Meijer <daan@studioseptember.nl>
* [modbus] connection closing behaviour finetuned The binding closes TCP/serial connections connections as per user configuration. It is either - every time, immediately after a transaction (reconnectAfterMillis=0) - *after* a read/write transaction, if the connection has been open "too long" (configurable with reconnectAfterMillis) We have an obvious downside to this simple logic -- the connection can remain open "indefinitely" if there are no transactions occurring. With Modbus we are quite often dealing with PLCs and other embedded systems with limited resources, and "reserving" the connection is not always something we want. Previously (2.5.x branch) connections were also closed when - a regular poll task was unregistered (i.e. we stop reading regularly from a modbus server ("slave"). Since most users have regular polling in place, so this ensured that connections do get closed. In this commit, the behaviour is adjusted such that connections are closed when last communication interface pointing to the server/serial port (i.e. "endpoint") is close()'d. With modbus binding this basically means when the tcp or serial thing is removed / disabled, the connections is closed/freed, but only if it is the last thing pointing to that server or serial port. Since modbus.sunspec binding reuses modbus serial & tcp endpoint things, the same note applies for modbus.sunspec binding. This is change in functional behaviour but in a way is logical. We can further introduce to have "delayed"/"deferred"/"debounce" connection closing connections as per the setting reconnectAfterMillis even in situations where communication interface is still open. * [modbus] Check and disconnect idle connections without transactions * [modbus] mvn spotless:apply * [modbubs] Fixed log message * [modbus] Race condition fix The CountDownLatch was used as a guard (latch.await) in many tests to wait for callbacks to be called before proceeding with assertions. Since the latch was countDown() beginning of the callback, we introduced a race condition with the subsequent assertions and updating the other counters used in the subsequent assertions. This commit updates the CountDownLatch as the last step of the callback, resolving the race condition. * [modbus] small test fix * [modbus] readcallback changed to nonnull * [modbus] Refactored ModbusCommunicationInterface to have seperate callback for result and failure However I had to dig deep to reach all the affected parts. Also there is a new callback, and a new "result" type to communicate the failures. * [modbus] SmokeTest refactored to new api * [modbus] Modbus bundle refactored to use the new api * [modbus][sunspec] refactored sunspec bundle to use the new modbus API * [modbus] refactor modbus tests to use the new api * [modbus] Removed ModbusWriteCallback interface from ModbusDataThingHandler Also reset ModbusDataThingHandler testWriteHandling generic to it's original form * [modbus] ModbusDataThingHandler does not implement ModbusReadCallback anymore Instead it has a public onReadResult method. ModbusPollerThingHandler changed to work with ModbusDataThingHandler children. * [modbus] Fixed caching in ModbusPollerThingHandler * [modbus] read modbus data as Optionals * [modbus] toString for PollResult * [modbus] fixed confusing variable name * [modbus] Disallow null callbacks * [modbus] mvn spotless:apply * [modbus] Removing Nullable decorations * [modbus] submitOneTimeWrite simplification * [modbus] Less verbose logging * [modbus] submitOneTimePoll simplification * [modbus] Less verbose logging * [modbus] Many null warnings removed * [modbus] Fix: no need for a @nonnull annotation because it is default * [modbus] Removing unneeded Nullable, using final in immutables * [modbus] Explicit functional interface * [modbus] @nullable and @NonNullByDefault aligned with coding conventions * [modbus] Collections.emptyMap instead of allocating new map every time. Signed-off-by: Sami Salonen <ssalonen@gmail.com> Co-authored-by: Nagy Attila Gábor <mrbig@sneaker.hu>
Co-authored with @mrbig, user feedback from @Rossko57 .
As discussed in openhab/openhab-core#1435 (comment).
This is a rather large PR, with the aim of improving the modbus transport API developer experience based on feedback from @mrbig and sunspec bundle.
The main changes introduced:
@Functional
, allowing binding developer to use lambdas and much less verbose way to access the data read. The API is vaguely modeled after vertx AsyncResult: https://vertx.io/docs/apidocs/io/vertx/core/AsyncResult.htmlPreviously one had to have callback with three methods, but depending on the type of request, only two methods are actually applicable.
BasicPollTaskImpl
. See example aboveThe above changes are not introducing any changes in behaviour.
There is also an API change which is changing slightly how to interact with transport API: introduction of ModbusCommunicationInterface.
Now, the transport API consumers need to "open" a ModbusCommunicationInterface to interact with a particular Modbus server ("slaves"). Modbus slaves are identified by
tcphost:tcpport
orserialport
. Once you have been finished interacting with the slave, youclose()
the communication interface. There can be many communication interfaces open to the same slave.Closing the communication interface signals to transport bundle that you are not expecting any further requests for a while. The transport bundle automatically frees resources (e.g. disconnects TCP connections) immediately if the last communication interface pointing to a server is closed.
The eager cleanup of resources was one of the main motivations for this change. In addition, some of the API details became simpler as well (e.g. error handling when there are conflicting baud rates trying to be associated with the same serial port).
In practice, the communication interface is held by the thing representing the modbus slave ("tcp" or "serial" thing). Once the thing is disposed, also the communication interface is closed.
Third change is improving automatic disconnection of unused idle connections. Previously connection age was checked after every request, and disconnected if older than the configured value. This had the downside that connection pool can contain open old connections when there are no transactions.
Now, the connection pool is inspected every 10 seconds, and old idle connections are disconnected.
For the user this is quite a transparent change, and should just mean that openHAB is not keeping any connections for long periods of time.