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

fix(device): prevent exception on network failure #291

Closed
wants to merge 7 commits into from

Conversation

rokam
Copy link
Contributor

@rokam rokam commented Sep 6, 2024

Fixes: #290

Summary by CodeRabbit

  • New Features

    • Introduced a new method for improved socket state management, enhancing message reception handling.
  • Bug Fixes

    • Enhanced error handling for connection issues with a retry mechanism, improving reliability during connection failures.

Copy link
Contributor

coderabbitai bot commented Sep 6, 2024

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The changes enhance the _check_state and run methods in the Device class of midealocal/device.py. A new private method _check_state is introduced to manage socket state and message reception, while the run method improves error handling for connection issues by implementing a retry mechanism with exponential backoff.

Changes

Files Change Summary
midealocal/device.py Added _check_state method for socket state management and improved error handling in run method.

Assessment against linked issues

Objective Addressed Explanation
Cannot reconnect after power loss (#290)

Possibly related PRs

Poem

In the garden where I hop and play,
Changes come to brighten the day.
With connections strong and retries fair,
My dehumidifier breathes fresh air!
Hooray for code that helps us thrive,
Now every device can feel alive! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot added the bug Something isn't working label Sep 6, 2024
@codecov-commenter
Copy link

codecov-commenter commented Sep 6, 2024

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

Attention: Patch coverage is 2.81690% with 69 lines in your changes missing coverage. Please review.

Project coverage is 39.97%. Comparing base (e0e6370) to head (9489cd2).
Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
midealocal/device.py 2.81% 69 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #291      +/-   ##
==========================================
+ Coverage   37.79%   39.97%   +2.17%     
==========================================
  Files          84       84              
  Lines        7477     7515      +38     
==========================================
+ Hits         2826     3004     +178     
+ Misses       4651     4511     -140     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 4e5d61c and 5e78508.

Files selected for processing (1)
  • midealocal/device.py (2 hunks)

midealocal/device.py Outdated Show resolved Hide resolved
midealocal/device.py Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 5e78508 and bd657c5.

Files selected for processing (1)
  • midealocal/device.py (2 hunks)
Files skipped from review as they are similar to previous changes (1)
  • midealocal/device.py

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between bd657c5 and 3e58de3.

Files selected for processing (1)
  • midealocal/device.py (3 hunks)

midealocal/device.py Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 3e58de3 and 6744d37.

Files selected for processing (1)
  • midealocal/device.py (3 hunks)
Additional comments not posted (1)
midealocal/device.py (1)

204-232: Approve changes in the connect method.

The modifications to the connect method enhance its robustness by handling various exceptions and logging them appropriately. The socket timeout is set to a reasonable value, which is suitable for network operations.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 6744d37 and f7f797f.

Files selected for processing (1)
  • midealocal/device.py (3 hunks)

Comment on lines 522 to 539
def _check_state(self) -> ParseMessageResult:
if not self._socket:
_LOGGER.warning("[%s] Socket closed", self._device_id)
return ParseMessageResult.ERROR
now = time.time()
self._check_refresh(now)
self._check_heartbeat(now)
msg = self._socket.recv(512)
if len(msg) == 0:
if self._is_run:
_LOGGER.warning(
"[%s] Socket error - Connection closed by peer",
self._device_id,
)
self.close_socket()
return ParseMessageResult.ERROR
return self.parse_message(msg)

Copy link
Contributor

Choose a reason for hiding this comment

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

Review of the _check_state method with suggestions for enhanced error handling.

The _check_state method has been significantly modified to handle socket state checks and message parsing more robustly. The method now includes checks for socket closure and empty messages, which are correctly handled by logging warnings and closing the socket if necessary.

However, the method could benefit from additional error handling, particularly in managing exceptions that may occur during message reception or parsing.

Consider adding exception handling around the message reception and parsing to prevent the thread from exiting unexpectedly on exceptions:

- msg = self._socket.recv(512)
- if len(msg) == 0:
+ try:
+     msg = self._socket.recv(512)
+     if len(msg) == 0:
+         if self._is_run:
+             _LOGGER.warning(
+                 "[%s] Socket error - Connection closed by peer",
+                 self._device_id,
+             )
+             self.close_socket()
+         return ParseMessageResult.ERROR
+ except OSError as e:
+     _LOGGER.warning("[%s] Failed to receive message: %s", self._device_id, str(e))
+     self.close_socket()
+     return ParseMessageResult.ERROR
+ except Exception as e:
+     _LOGGER.exception("[%s] Unexpected error during message reception: %s", self._device_id, str(e))
+     self.close_socket()
+     return ParseMessageResult.ERROR

This change ensures that all potential exceptions during message reception are caught and handled appropriately, preventing the thread from terminating unexpectedly and allowing for more graceful error recovery.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _check_state(self) -> ParseMessageResult:
if not self._socket:
_LOGGER.warning("[%s] Socket closed", self._device_id)
return ParseMessageResult.ERROR
now = time.time()
self._check_refresh(now)
self._check_heartbeat(now)
msg = self._socket.recv(512)
if len(msg) == 0:
if self._is_run:
_LOGGER.warning(
"[%s] Socket error - Connection closed by peer",
self._device_id,
)
self.close_socket()
return ParseMessageResult.ERROR
return self.parse_message(msg)
def _check_state(self) -> ParseMessageResult:
if not self._socket:
_LOGGER.warning("[%s] Socket closed", self._device_id)
return ParseMessageResult.ERROR
now = time.time()
self._check_refresh(now)
self._check_heartbeat(now)
try:
msg = self._socket.recv(512)
if len(msg) == 0:
if self._is_run:
_LOGGER.warning(
"[%s] Socket error - Connection closed by peer",
self._device_id,
)
self.close_socket()
return ParseMessageResult.ERROR
except OSError as e:
_LOGGER.warning("[%s] Failed to receive message: %s", self._device_id, str(e))
self.close_socket()
return ParseMessageResult.ERROR
except Exception as e:
_LOGGER.exception("[%s] Unexpected error during message reception: %s", self._device_id, str(e))
self.close_socket()
return ParseMessageResult.ERROR
return self.parse_message(msg)

Comment on lines 204 to 232
try:
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.settimeout(10)
_LOGGER.debug(
"[%s] Connecting to %s:%s",
self._device_id,
self._ip_address,
self._port,
)
self._socket.connect((self._ip_address, self._port))
_LOGGER.debug("[%s] Connected", self._device_id)
connected = True
except TimeoutError:
_LOGGER.debug("[%s] Connection timed out", self._device_id)
except OSError:
_LOGGER.debug("[%s] Connection error", self._device_id)
except Exception as e:
file = None
lineno = None
if e.__traceback__:
file = e.__traceback__.tb_frame.f_globals["__file__"] # pylint: disable=E1101
lineno = e.__traceback__.tb_lineno
_LOGGER.exception(
"[%s] Unknown error : %s, %s",
self._device_id,
file,
lineno,
)
self.set_available(connected)
Copy link
Contributor

Choose a reason for hiding this comment

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

Review of the connect method with suggestions for error handling improvements.

The connect method has been updated to handle various exceptions more gracefully by logging them. However, the handling of generic exceptions could be improved by providing more specific error messages or handling specific cases differently.

Consider refining the exception handling to provide more actionable insights or recover from specific errors when possible. For example, network-related exceptions could trigger a re-attempt or a different recovery mechanism.

Here's a proposed change to enhance the exception handling:

- except Exception as e:
-     file = None
-     lineno = None
-     if e.__traceback__:
-         file = e.__traceback__.tb_frame.f_globals["__file__"]  # pylint: disable=E1101
-         lineno = e.__traceback__.tb_lineno
-     _LOGGER.exception(
-         "[%s] Unknown error : %s, %s",
-         self._device_id,
-         file,
-         lineno,
-     )
+ except Exception as e:
+     _LOGGER.exception("[%s] Unexpected error occurred: %s", self._device_id, str(e))

This change simplifies the logging and focuses on the exception message, which is typically sufficient for debugging unexpected errors.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try:
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.settimeout(10)
_LOGGER.debug(
"[%s] Connecting to %s:%s",
self._device_id,
self._ip_address,
self._port,
)
self._socket.connect((self._ip_address, self._port))
_LOGGER.debug("[%s] Connected", self._device_id)
connected = True
except TimeoutError:
_LOGGER.debug("[%s] Connection timed out", self._device_id)
except OSError:
_LOGGER.debug("[%s] Connection error", self._device_id)
except Exception as e:
file = None
lineno = None
if e.__traceback__:
file = e.__traceback__.tb_frame.f_globals["__file__"] # pylint: disable=E1101
lineno = e.__traceback__.tb_lineno
_LOGGER.exception(
"[%s] Unknown error : %s, %s",
self._device_id,
file,
lineno,
)
self.set_available(connected)
try:
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.settimeout(10)
_LOGGER.debug(
"[%s] Connecting to %s:%s",
self._device_id,
self._ip_address,
self._port,
)
self._socket.connect((self._ip_address, self._port))
_LOGGER.debug("[%s] Connected", self._device_id)
connected = True
except TimeoutError:
_LOGGER.debug("[%s] Connection timed out", self._device_id)
except OSError:
_LOGGER.debug("[%s] Connection error", self._device_id)
except Exception as e:
_LOGGER.exception("[%s] Unexpected error occurred: %s", self._device_id, str(e))
self.set_available(connected)

@wuwentao
Copy link
Member

wuwentao commented Sep 9, 2024

@rokam add some changes to improve it .

  1. change log level from warning to debug, as all the device init connect will report a warning log after HA reboot
  2. use while loop before socket is available, as connect only need when self._socket is None
  3. update the self._authenticate_refresh_capabilities() order only when first time connect, if refresh_status and self.socket is not none, skip self._authenticate_refresh_capabilities()

one more comments:
if i change while self._socket is None: to if self._socket is None:
mypy will report error as :

mypy.....................................................................Failed
- hook id: mypy
- exit code: 1

midealocal/device.py:562: error: Item "None" of "socket | None" has no attribute "settimeout"  [union-attr]
Found 1 error in 1 file (checked 1 source file)

@wuwentao
Copy link
Member

update: add try/except to all the socket send/recv, try to catch the exception and close socket, the next loop will reconnect when socket is none.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between f7f797f and 7fdf0db.

Files selected for processing (1)
  • midealocal/device.py (5 hunks)
Additional comments not posted (1)
midealocal/device.py (1)

281-289: LGTM!

The exception handling in send_message_v2 looks good. It logs the exception and closes the socket, which is appropriate for handling unexpected errors during message sending.

Comment on lines 577 to 600
connection_retries = 0
while self._is_run:
if not self.connect():
raise CannotConnect
if not self._socket:
raise SocketException
self._authenticate_refresh_capabilities()
while self._socket is None:
_LOGGER.debug("[%s] No open socket, try to connect", self._device_id)
if not self.connect():
self.close_socket()
connection_retries += 1
sleep_time = min(60 * connection_retries, 600)
_LOGGER.warning(
"[%s] Unable to connect, sleep %s seconds",
self._device_id,
sleep_time,
)
time.sleep(sleep_time)
continue
self._authenticate_refresh_capabilities()
connection_retries = 0
timeout_counter = 0
start = time.time()
self._previous_refresh = self._previous_heartbeat = start
self._socket.settimeout(1)
while True:
try:
now = time.time()
self._check_refresh(now)
self._check_heartbeat(now)
msg = self._socket.recv(512)
if len(msg) == 0:
if self._is_run:
_LOGGER.error(
"[%s] Socket error - Connection closed by peer",
self._device_id,
)
self.close_socket()
break
result = self.parse_message(msg)
result = self._check_state()
Copy link
Contributor

Choose a reason for hiding this comment

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

Approve the modifications in run method with a suggestion for improving connection retry logic.

The modifications to the run method significantly enhance its robustness by implementing a retry mechanism with exponential backoff. This is crucial for maintaining connectivity under network instability.

However, the method could be further refined to handle exceptions more gracefully and to ensure that the connection retries do not lead to resource exhaustion or overly long wait times.

Consider refining the exponential backoff mechanism to include a maximum retry limit and to handle exceptions more gracefully:

- while self._is_run:
-     while self._socket is None:
-         _LOGGER.debug("[%s] No open socket, try to connect", self._device_id)
-         if not self.connect():
-             self.close_socket()
-             connection_retries += 1
-             sleep_time = min(60 * connection_retries, 600)
-             _LOGGER.warning(
-                 "[%s] Unable to connect, sleep %s seconds",
-                 self._device_id,
-                 sleep_time,
-             )
-             time.sleep(sleep_time)
-             continue
-         self._authenticate_refresh_capabilities()
+ while self._is_run and connection_retries < MAX_RETRIES:
+     if self._socket is None and not self.connect():
+         connection_retries += 1
+         sleep_time = min(60 * connection_retries, 600)
+         _LOGGER.warning(
+             "[%s] Unable to connect, retry %d/%d, sleeping for %s seconds",
+             self._device_id,
+             connection_retries,
+             MAX_RETRIES,
+             sleep_time,
+         )
+         time.sleep(sleep_time)
+     else:
+         connection_retries = 0
+         self._authenticate_refresh_capabilities()
+         # Handle socket operations here

This change introduces a maximum retry limit (MAX_RETRIES) to prevent infinite retry loops and provides more detailed logging that includes the current retry count and the maximum allowed retries. It also simplifies the control flow by reducing nested conditions.

Committable suggestion was skipped due to low confidence.

Comment on lines +224 to +237
except Exception as e:
file = None
lineno = None
if e.__traceback__:
file = e.__traceback__.tb_frame.f_globals["__file__"] # pylint: disable=E1101
lineno = e.__traceback__.tb_lineno
_LOGGER.exception(
"[%s] Unknown error : %s, %s",
self._device_id,
file,
lineno,
)
# set _socket to None when connect exception matched
self._socket = None
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider refining the exception handling to provide more actionable insights or recover from specific errors when possible.

The handling of generic exceptions could be improved by providing more specific error messages or handling specific cases differently. For example, network-related exceptions could trigger a re-attempt or a different recovery mechanism.

Here's a proposed change to enhance the exception handling:

- except Exception as e:
-     file = None
-     lineno = None
-     if e.__traceback__:
-         file = e.__traceback__.tb_frame.f_globals["__file__"]  # pylint: disable=E1101
-         lineno = e.__traceback__.tb_lineno
-     _LOGGER.exception(
-         "[%s] Unknown error : %s, %s",
-         self._device_id,
-         file,
-         lineno,
-     )
+ except Exception as e:
+     _LOGGER.exception("[%s] Unexpected error occurred: %s", self._device_id, str(e))

This change simplifies the logging and focuses on the exception message, which is typically sufficient for debugging unexpected errors.

Committable suggestion was skipped due to low confidence.

Comment on lines +544 to +573
def _check_state(self) -> ParseMessageResult:
if not self._socket:
_LOGGER.warning("[%s] Socket closed", self._device_id)
return ParseMessageResult.ERROR
now = time.time()
self._check_refresh(now)
self._check_heartbeat(now)
try:
msg = self._socket.recv(512)
if len(msg) == 0:
if self._is_run:
_LOGGER.warning(
"[%s] Socket error - Connection closed by peer",
self._device_id,
)
self.close_socket()
return ParseMessageResult.ERROR
return self.parse_message(msg)
except TimeoutError:
_LOGGER.debug("[%s] _check_state Socket timed out", self._device_id)
self.close_socket()
return ParseMessageResult.ERROR
except Exception as e:
_LOGGER.exception(
"[%s] Unexpected socket error",
self._device_id,
exc_info=e,
)
self.close_socket()
return ParseMessageResult.ERROR
Copy link
Contributor

Choose a reason for hiding this comment

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

Approve the new _check_state method with suggestions for enhanced error handling.

The _check_state method significantly improves the code by consolidating the logic for socket state checks and message parsing. The method includes appropriate checks for socket closure and empty messages, which are handled by logging warnings and closing the socket if necessary.

However, the method could benefit from additional error handling, particularly in managing exceptions that may occur during message reception or parsing.

Consider adding exception handling around the message reception and parsing to prevent the thread from exiting unexpectedly on exceptions:

- msg = self._socket.recv(512)
- if len(msg) == 0:
+ try:
+     msg = self._socket.recv(512)
+     if len(msg) == 0:
+         if self._is_run:
+             _LOGGER.warning(
+                 "[%s] Socket error - Connection closed by peer",
+                 self._device_id,
+             )
+             self.close_socket()
+         return ParseMessageResult.ERROR
+ except OSError as e:
+     _LOGGER.warning("[%s] Failed to receive message: %s", self._device_id, str(e))
+     self.close_socket()
+     return ParseMessageResult.ERROR  
+ except Exception as e:
+     _LOGGER.exception("[%s] Unexpected error during message reception: %s", self._device_id, str(e))
+     self.close_socket()
+     return ParseMessageResult.ERROR

This change ensures that all potential exceptions during message reception are caught and handled appropriately, preventing the thread from terminating unexpectedly and allowing for more graceful error recovery.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _check_state(self) -> ParseMessageResult:
if not self._socket:
_LOGGER.warning("[%s] Socket closed", self._device_id)
return ParseMessageResult.ERROR
now = time.time()
self._check_refresh(now)
self._check_heartbeat(now)
try:
msg = self._socket.recv(512)
if len(msg) == 0:
if self._is_run:
_LOGGER.warning(
"[%s] Socket error - Connection closed by peer",
self._device_id,
)
self.close_socket()
return ParseMessageResult.ERROR
return self.parse_message(msg)
except TimeoutError:
_LOGGER.debug("[%s] _check_state Socket timed out", self._device_id)
self.close_socket()
return ParseMessageResult.ERROR
except Exception as e:
_LOGGER.exception(
"[%s] Unexpected socket error",
self._device_id,
exc_info=e,
)
self.close_socket()
return ParseMessageResult.ERROR
def _check_state(self) -> ParseMessageResult:
if not self._socket:
_LOGGER.warning("[%s] Socket closed", self._device_id)
return ParseMessageResult.ERROR
now = time.time()
self._check_refresh(now)
self._check_heartbeat(now)
try:
try:
msg = self._socket.recv(512)
if len(msg) == 0:
if self._is_run:
_LOGGER.warning(
"[%s] Socket error - Connection closed by peer",
self._device_id,
)
self.close_socket()
return ParseMessageResult.ERROR
except OSError as e:
_LOGGER.warning("[%s] Failed to receive message: %s", self._device_id, str(e))
self.close_socket()
return ParseMessageResult.ERROR
except Exception as e:
_LOGGER.exception("[%s] Unexpected error during message reception: %s", self._device_id, str(e))
self.close_socket()
return ParseMessageResult.ERROR
return self.parse_message(msg)
except TimeoutError:
_LOGGER.debug("[%s] _check_state Socket timed out", self._device_id)
self.close_socket()
return ParseMessageResult.ERROR
except Exception as e:
_LOGGER.exception(
"[%s] Unexpected socket error",
self._device_id,
exc_info=e,
)
self.close_socket()
return ParseMessageResult.ERROR

@wuwentao wuwentao marked this pull request as draft September 12, 2024 09:58
@wuwentao
Copy link
Member

mark to draft as the timeout and process is error, need to continue work on it. will finish it ASAP and mark to ready for review

@rokam
Copy link
Contributor Author

rokam commented Sep 19, 2024

Replaced by #296

@rokam rokam closed this Sep 19, 2024
@wuwentao wuwentao deleted the fix-cannot-connect branch October 9, 2024 06:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot connect
4 participants