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

Handling BrokenPipeError with meshtastic TCPInterface #727

Closed
rickoooooo opened this issue Dec 29, 2024 · 2 comments
Closed

Handling BrokenPipeError with meshtastic TCPInterface #727

rickoooooo opened this issue Dec 29, 2024 · 2 comments

Comments

@rickoooooo
Copy link

I've been working on a Python project which uses this Meshtastic Python API. I noticed that my project regularly crashes with the below stack trace. I believe what's happening is that the Meshtastic radio only permits a single TCP connection at a time. If anything else on the network connects to the Meshtastic radio, then my project is disconnected. The API does not seem to recognize or handle this and my project is no longer able to communicate with the radio. It results in an unhandled exception when the heartbeat fails. I'm unsure if there's some way I can catch and handle this in my own code, as it seems to be happening in a thread inside the Meshtastic library itself. Ideally the disconnection would be recognized immeditaely so a connection could be re-established. Any suggestions are appreciated!

DEBUG:root:Sending heartbeat, interval 300 seconds
DEBUG:root:Sending: heartbeat { }
DEBUG:root:sending header:b'\x94\xc3\x00\x02' b:b':\x00'
Exception in thread Thread-4:
Traceback (most recent call last):
  File "/usr/lib/python3.12/threading.py", line 1075, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.12/threading.py", line 1433, in run
    self.function(*self.args, **self.kwargs)
  File "/usr/lib/python3.12/site-packages/meshtastic/mesh_interface.py", line 906, in callback
    self.sendHeartbeat()
  File "/usr/lib/python3.12/site-packages/meshtastic/mesh_interface.py", line 895, in sendHeartbeat
    self._sendToRadio(p)
  File "/usr/lib/python3.12/site-packages/meshtastic/mesh_interface.py", line 970, in _sendToRadio
    self._sendToRadioImpl(toRadio)
  File "/usr/lib/python3.12/site-packages/meshtastic/stream_interface.py", line 120, in _sendToRadioImpl
    self._writeBytes(header + b)
  File "/usr/lib/python3.12/site-packages/meshtastic/tcp_interface.py", line 79, in _writeBytes
    self.socket.send(b)
BrokenPipeError: [Errno 32] Broken pipe
@rickoooooo
Copy link
Author

I think I've worked around the problem by setting up a thread to just test the TCP connection every second and then restart the TCPInterface if there's an exception. This feels hacky to me, though. If there's a way to identify a broken connection in the library itself, that might be a cleaner way to handle it?

The below code is what I'm using, but it's somewhat specific to my project. Including it below in case it may be helpful to anyone else. It was adapted from a StackOverflow post.

    def check_socket_closed(self) -> bool:
        while True:
            sock = self.interface.socket
            try:
                # this will try to read bytes without blocking and also without removing them from buffer (peek only)
                data = sock.recv(16, socket.MSG_DONTWAIT | socket.MSG_PEEK)
                if len(data) == 0:
                    self.socket_reset()
            except BlockingIOError:
                pass  # socket is open and reading from it would block
            except ConnectionResetError:
                self.socket_reset()  # socket was closed for some other reason
            except Exception as e:
                logger.error(str(e))
                pass
            time.sleep(1)

    def socket_reset(self) -> None:
        self.interface.close()
        self.interface = meshtastic.tcp_interface.TCPInterface(self.radio_ip)

@rickoooooo
Copy link
Author

I somehow missed that there is a meshtastic.connection.lost topic which is triggered on disconnect. That is probably the intended way to handle this. I'll go ahead and close this issue.

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

No branches or pull requests

1 participant