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

Tunnel Refactoring #443

Merged
merged 7 commits into from
Dec 21, 2020
Merged

Tunnel Refactoring #443

merged 7 commits into from
Dec 21, 2020

Conversation

farmio
Copy link
Member

@farmio farmio commented Oct 1, 2020

  • Tunnel connections process DisconnectRequest now and closes/reconnects the tunnel when the other side closes gracefully
  • XKNX.connected Event can be used in future to await for a working connection or stop/relaunch tasks if the connection is lost (I'd like to use this eg. for StateUpdater and DateTime broadcast)
  • Lower heartbeat rate from every 15sec to every 70 sec and raise ConnectionstateRequest timeout from 1 to 10sec (3/8/1 KNXip Overview §5.8 Timeout Constants). There are 3 retrys so 90 + 10 (initial connectionstate request) + 3x 10 (retrys) = 80 - 10 seconds spare = 80 . We will probably not need to rely on the heartbeat to detect lost connections anymore because we process DisconnectRequests now.
  • clean up Tunnel class

closes #89

TODO:

  • on Error shut down the whole interface (and UDPClient) and create a new one from KNXIPInterface so the connection_config can be read again. This would enable to connect to (or from) a different IP, KNX/IP Interface or even connection type when one interface fails.

  • CONNECT_REQUEST_TIMEOUT should be 10 seconds instead of 1 according to the specs

  • call Tunnel._tunnel_lost() from UDPClient error_received ( callback / raise / contextmanager ...) - same for Routing

  • recreate log messages and errors

  • write tests!

Known issues:

  • When using daemon_mode and auto_reconnect=False (which is a very unlikely scenario imho) the XKNX context manager does not return on a lost connection. It hangs waiting for SIGINT. On SIGINT it tries to call Tunnel.stop() which fails.

  • This probably needs a lot of testing under rough conditions 😬

@coveralls
Copy link

coveralls commented Oct 1, 2020

Coverage Status

Coverage decreased (-0.2%) to 94.597% when pulling de66e32 on farmio:knxip-interface into 30720c7 on XKNX:master.

Copy link
Member

@marvin-w marvin-w left a comment

Choose a reason for hiding this comment

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

I like the idea, however there are still some open points and I also haven't tested this yet.

It would make sense to add a dedicated context manager.

Also, from experience I can safely say that refactoring a mostly untested class is very highly going to cause integration issues.

xknx/io/tunnel.py Outdated Show resolved Hide resolved
xknx/xknx.py Show resolved Hide resolved
#
# CONNECT DISCONNECT
#
####################

async def start(self):
Copy link
Member

Choose a reason for hiding this comment

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

I like the idea. Since you now have dedicated start and stop functions it would probably make sense to add an async context manager to it and adjust the examples as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

I sure like the idea. But for now I aim for a stable and reliable connection. Since this is not very likely to be used directly I think syntactic sugar can be added later.

@@ -34,16 +34,14 @@ async def main():
gateway_port=gateway.port,
)

await tunnel.connect_udp()
await tunnel.connect()
await tunnel.start()
Copy link
Member

Choose a reason for hiding this comment

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

async with tunnel: <3

@farmio farmio marked this pull request as draft October 4, 2020 07:43
@farmio farmio marked this pull request as ready for review December 11, 2020 10:10
@farmio
Copy link
Member Author

farmio commented Dec 11, 2020

I think it works fine now. Maybe someone else can test it for a while?

One thing I still want to change here is:

on Error (eg. OSError when there is no network connections) shut down the whole interface (and UDPClient) and create a new one from KNXIPInterface so the connection_config can be read again. This would enable to connect to (or from) a different IP, KNX/IP Interface or even connection type when one interface fails. Also when for some reason the interface gets a new IP address it would be able to connect to it when connection_config is set appropriately.

But this should maybe be done in an extra PR.

try:
await self.udp_client.connect()
await self._connect_request()
except (OSError, CommunicationError) as ex:
Copy link
Member Author

@farmio farmio Dec 17, 2020

Choose a reason for hiding this comment

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

closes #89 😉

- Tunnel connections process DisconnectRequest now and closes/reconnects the tunnel
- xknx.connected Event can be used in future to await for a working connection
- lower heartbeat rate from every 15sec to 70 sec
@farmio farmio merged commit cbc0c30 into XKNX:master Dec 21, 2020
@farmio farmio deleted the knxip-interface branch January 5, 2022 15:13
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.

Catch network errors when setting up tunnel
3 participants