Console settings: add post-update verification in with_retry flows; introduce _verify_console_param_value and use it to verify retain final state, general params, and RuleN enable; keep non-retry path behavior. Improves reliability and ensures updates actually took.
This commit is contained in:
parent
9646099a4f
commit
d4b29c2359
@ -1458,8 +1458,15 @@ class TasmotaDiscovery:
|
||||
response = requests.get(url, timeout=5)
|
||||
if response.status_code == 200:
|
||||
self.logger.debug(f"{name}: Set {param} to {final_value} (step 2 of 2 to update MQTT broker retain settings)")
|
||||
console_updated = True
|
||||
success = True
|
||||
# Verify the change took effect
|
||||
verified = self._verify_console_param_value(ip, name, param, final_value)
|
||||
if verified:
|
||||
console_updated = True
|
||||
success = True
|
||||
else:
|
||||
self.logger.warning(f"{name}: Verification failed for {param} after update; retrying (attempt {attempts}/{max_attempts})")
|
||||
if attempts < max_attempts:
|
||||
time.sleep(1)
|
||||
else:
|
||||
self.logger.warning(f"{name}: Failed to set {param} to {final_value} (attempt {attempts}/{max_attempts})")
|
||||
last_error = f"HTTP {response.status_code}"
|
||||
@ -1596,8 +1603,14 @@ class TasmotaDiscovery:
|
||||
self.logger.info(f"{name}: Set rule {param} to '{value}'")
|
||||
else:
|
||||
self.logger.debug(f"{name}: Set console parameter {param} to {value}")
|
||||
console_updated = True
|
||||
success = True
|
||||
# Verify the change took effect before marking success
|
||||
if self._verify_console_param_value(ip, name, param, value):
|
||||
console_updated = True
|
||||
success = True
|
||||
else:
|
||||
self.logger.warning(f"{name}: Verification failed for {param} after update; retrying (attempt {attempts}/{max_attempts})")
|
||||
if attempts < max_attempts:
|
||||
time.sleep(1)
|
||||
else:
|
||||
self.logger.warning(f"{name}: Failed to set console parameter {param} (attempt {attempts}/{max_attempts})")
|
||||
last_error = f"HTTP {response.status_code}"
|
||||
@ -1685,8 +1698,13 @@ class TasmotaDiscovery:
|
||||
response = requests.get(url, timeout=5)
|
||||
if response.status_code == 200:
|
||||
self.logger.info(f"{name}: Auto-enabled {rule_enable_param}")
|
||||
console_updated = True
|
||||
success = True
|
||||
if self._verify_console_param_value(ip, name, rule_enable_param, "1"):
|
||||
console_updated = True
|
||||
success = True
|
||||
else:
|
||||
self.logger.warning(f"{name}: Verification failed for {rule_enable_param} after update; retrying (attempt {attempts}/{max_attempts})")
|
||||
if attempts < max_attempts:
|
||||
time.sleep(1)
|
||||
else:
|
||||
self.logger.warning(f"{name}: Failed to auto-enable {rule_enable_param} (attempt {attempts}/{max_attempts})")
|
||||
last_error = f"HTTP {response.status_code}"
|
||||
@ -1724,6 +1742,50 @@ class TasmotaDiscovery:
|
||||
|
||||
return console_updated
|
||||
|
||||
def _verify_console_param_value(self, ip, name, param, expected):
|
||||
"""Post-update verification; returns True if device value equals expected.
|
||||
Normalizes values:
|
||||
- ruleN (lowercase) compare rules text (case/whitespace-insensitive)
|
||||
- RuleN (uppercase) consider ON/1/enabled as True when expected is truthy ('1','on')
|
||||
- Generic: normalize 'on'/'off' vs '1'/'0'
|
||||
"""
|
||||
try:
|
||||
cur, ok = self._get_console_param_value(ip, name, param)
|
||||
if not ok:
|
||||
return False
|
||||
# Rule definition verify
|
||||
if param.lower().startswith('rule') and param.islower() and param[-1].isdigit():
|
||||
import re as _re
|
||||
def _norm(s):
|
||||
s = str(s or '')
|
||||
s = s.strip().lower()
|
||||
s = _re.sub(r"\s+", " ", s)
|
||||
return s
|
||||
return _norm(cur) == _norm(expected)
|
||||
# Rule enable verify (RuleN)
|
||||
if param.lower().startswith('rule') and not param.islower() and param[-1].isdigit():
|
||||
val = str(cur or '').strip().lower()
|
||||
if val in ('on','enabled','active'):
|
||||
val = '1'
|
||||
if val in ('off','disabled','inactive'):
|
||||
val = '0'
|
||||
exp = str(expected or '').strip().lower()
|
||||
if exp in ('on','enabled','active'):
|
||||
exp = '1'
|
||||
if exp in ('off','disabled','inactive'):
|
||||
exp = '0'
|
||||
return val == exp or val == '1'
|
||||
# Generic verify
|
||||
val = str(cur or '').strip().lower()
|
||||
exp = str(expected or '').strip().lower()
|
||||
if val in ('on','off') and exp in ('1','0'):
|
||||
val = '1' if val=='on' else '0'
|
||||
if val in ('1','0') and exp in ('on','off'):
|
||||
val = 'on' if val=='1' else 'off'
|
||||
return val == exp
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _get_console_param_value(self, ip, name, param):
|
||||
"""Query the device for the current value of a console parameter.
|
||||
Returns (value, True) on success, (None, False) on failure.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user