Skip to content

Repeating the EVSE readout process in case of a timeout/error to prevent unnecessary log entries#3175

Merged
LKuemmel merged 1 commit intoopenWB:masterfrom
MBungalski:EVSE-Retry
Mar 6, 2026
Merged

Repeating the EVSE readout process in case of a timeout/error to prevent unnecessary log entries#3175
LKuemmel merged 1 commit intoopenWB:masterfrom
MBungalski:EVSE-Retry

Conversation

@MBungalski
Copy link
Contributor

Change in module hardware_check.py

Previously, if the EVSE failed to respond to a read operation using the "get_evse_state" function, an error message was immediately written to the log of the internal charging points. The routine was extended so that in this case of an error, the process is repeated twice. Now, the error is only written to the log after three failed attempts.

…ntwort der EVSE) bis zu zwei Mal nach einer Pause von 300ms wiederholt, bevor eine entsprechende Fehlermeldung "Auslesen der EVSE nicht möglich. Vermutlich ist die EVSE defekt oder hat eine unbekannte Modbus-ID." ins Log geschrieben wird.
@MBungalski MBungalski changed the title Repeating the EVSE readout process in case of an timeout/error to prevent unnecessary log entries Repeating the EVSE readout process in case of a timeout/error to prevent unnecessary log entries Mar 3, 2026
@LKuemmel LKuemmel merged commit 2ad27e3 into openWB:master Mar 6, 2026
1 check passed
@LKuemmel LKuemmel requested a review from Copilot March 6, 2026 12:41
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Extends the EVSE readout in hardware_check.py to retry EVSE state reads on failures before surfacing an error, aiming to reduce unnecessary error log entries for transient read issues.

Changes:

  • Adds time import to support retry backoff.
  • Wraps get_evse_state() in a 3-attempt loop with a short sleep between failed attempts.
  • Preserves existing downstream behavior (meter check + raising adapter/EVSE errors) while delaying EVSE failure escalation until after retries.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

evse_state = self.evse_client.get_evse_state()
evse_check_passed = True
break
except Exception as e:
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The retry loop catches and retries on any Exception. This will also retry non-transient errors (e.g., ValueError from Evse.get_plug_charge_state() when the EVSE reports an unknown state), delaying a real fault and potentially masking programming/configuration issues. Consider restricting retries to known transient Modbus/IO failures (e.g., pymodbus connection/io exceptions, or exceptions whose __cause__ is one of those), and fail fast for semantic errors like ValueError.

Suggested change
except Exception as e:
except (pymodbus.exceptions.ModbusIOException,
pymodbus.exceptions.ConnectionException) as e:

Copilot uses AI. Check for mistakes.
Comment on lines +87 to +99
for attempt in (1, 2, 3):
try:
with self.client:
evse_state = self.evse_client.get_evse_state()
evse_check_passed = True
break
except Exception as e:
evse_check_passed = self.handle_exception(e)
# Wenn nicht "handled" -> maximal zwei Wiederholungen
if attempt < 3 and evse_check_passed is False:
time.sleep(0.3)
continue
break
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

with self.client: is executed inside the retry loop, so a failing EVSE read can open/close (and potentially reconnect) up to 3 times. Previously this block ran once per hardware check. Consider entering the client context once (outside the loop) and retrying only the get_evse_state() call to avoid extra connection churn and reduce load/latency.

Suggested change
for attempt in (1, 2, 3):
try:
with self.client:
evse_state = self.evse_client.get_evse_state()
evse_check_passed = True
break
except Exception as e:
evse_check_passed = self.handle_exception(e)
# Wenn nicht "handled" -> maximal zwei Wiederholungen
if attempt < 3 and evse_check_passed is False:
time.sleep(0.3)
continue
break
with self.client:
for attempt in (1, 2, 3):
try:
evse_state = self.evse_client.get_evse_state()
evse_check_passed = True
break
except Exception as e:
evse_check_passed = self.handle_exception(e)
# Wenn nicht "handled" -> maximal zwei Wiederholungen
if attempt < 3 and evse_check_passed is False:
time.sleep(0.3)
continue
break

Copilot uses AI. Check for mistakes.
Comment on lines +86 to +99
# 2x Retry bei EVSE-Auslesen vor dem Absetzen einer Fehlermeldung
for attempt in (1, 2, 3):
try:
with self.client:
evse_state = self.evse_client.get_evse_state()
evse_check_passed = True
break
except Exception as e:
evse_check_passed = self.handle_exception(e)
# Wenn nicht "handled" -> maximal zwei Wiederholungen
if attempt < 3 and evse_check_passed is False:
time.sleep(0.3)
continue
break
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

This change makes request_and_check_hardware() call get_evse_state() up to 3 times. Existing unit tests/mocks that provide a single-item side_effect list for get_evse_state will now be exhausted (raising StopIteration) and may fail for the wrong reason. Update/add tests to cover: (1) success after 1–2 failures and (2) failure after 3 attempts, ideally also asserting the number of calls and that the delay is applied (with time.sleep mocked).

Copilot uses AI. Check for mistakes.
Comment on lines +86 to +98
# 2x Retry bei EVSE-Auslesen vor dem Absetzen einer Fehlermeldung
for attempt in (1, 2, 3):
try:
with self.client:
evse_state = self.evse_client.get_evse_state()
evse_check_passed = True
break
except Exception as e:
evse_check_passed = self.handle_exception(e)
# Wenn nicht "handled" -> maximal zwei Wiederholungen
if attempt < 3 and evse_check_passed is False:
time.sleep(0.3)
continue
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The retry configuration uses magic values (for attempt in (1, 2, 3) and time.sleep(0.3)). To make future tuning easier and avoid scattering policy in-line, consider extracting these into named constants (e.g., max_attempts / retry_delay_seconds) near the other module-level constants.

Copilot uses AI. Check for mistakes.
@MBungalski MBungalski deleted the EVSE-Retry branch March 7, 2026 15:10
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

Successfully merging this pull request may close these issues.

3 participants