Fix MQTT FullTopic with URL-encoded leading space
- Devices had FullTopic starting with %20 (URL-encoded space) - This breaks MQTT topic publishing with invalid leading space - Now detects %20 prefix and forces update even if normalized values match - Properly URL-encodes all MQTT setting values when sending - FullTopic %prefix%/%topic%/ now encoded as %25prefix%25%2F%25topic%25%2F - Fixes MQTT topics showing as '%20stat/device/...' instead of 'stat/device/...'
This commit is contained in:
parent
12ebdbf3e9
commit
be95930cd1
@ -225,18 +225,24 @@ class ConfigurationManager:
|
|||||||
current_full_topic = result.get('FullTopic', '') if success and result else ''
|
current_full_topic = result.get('FullTopic', '') if success and result else ''
|
||||||
|
|
||||||
self.logger.debug(f"{device_name}: Raw FullTopic from device: '{current_full_topic}'")
|
self.logger.debug(f"{device_name}: Raw FullTopic from device: '{current_full_topic}'")
|
||||||
|
|
||||||
|
# Check if device has URL-encoded spaces at the beginning (broken state)
|
||||||
|
has_leading_encoded_space = current_full_topic.startswith('%20')
|
||||||
|
|
||||||
# Normalize: remove any URL-encoded spaces from the beginning of current value
|
# Normalize: remove any URL-encoded spaces from the beginning of current value
|
||||||
# This handles the case where the device returns '%20%prefix%' instead of '%prefix%'
|
# This handles the case where the device returns '%20%prefix%' instead of '%prefix%'
|
||||||
while current_full_topic.startswith('%20'):
|
while current_full_topic.startswith('%20'):
|
||||||
current_full_topic = current_full_topic[3:]
|
current_full_topic = current_full_topic[3:]
|
||||||
|
|
||||||
# Also normalize expected value in case config has leading spaces
|
# Also normalize expected value in case config has leading spaces
|
||||||
mqtt_full_topic_normalized = mqtt_full_topic.lstrip()
|
mqtt_full_topic_normalized = mqtt_full_topic.lstrip()
|
||||||
|
|
||||||
self.logger.debug(f"{device_name}: Comparing FullTopic: current='{current_full_topic}' vs expected='{mqtt_full_topic_normalized}'")
|
self.logger.debug(f"{device_name}: Comparing FullTopic: current='{current_full_topic}' vs expected='{mqtt_full_topic_normalized}'")
|
||||||
|
|
||||||
if current_full_topic != mqtt_full_topic_normalized:
|
# Update if values don't match OR if device had leading encoded space (needs fixing)
|
||||||
|
if current_full_topic != mqtt_full_topic_normalized or has_leading_encoded_space:
|
||||||
|
if has_leading_encoded_space:
|
||||||
|
self.logger.info(f"{device_name}: FullTopic has invalid leading space, will fix")
|
||||||
updates_needed.append(('FullTopic', mqtt_full_topic_normalized))
|
updates_needed.append(('FullTopic', mqtt_full_topic_normalized))
|
||||||
|
|
||||||
# Handle NoRetain (SetOption62)
|
# Handle NoRetain (SetOption62)
|
||||||
@ -255,8 +261,14 @@ class ConfigurationManager:
|
|||||||
|
|
||||||
failed_updates = []
|
failed_updates = []
|
||||||
for setting_name, setting_value in updates_needed:
|
for setting_name, setting_value in updates_needed:
|
||||||
command = f"{setting_name}%20{setting_value}"
|
# URL encode the value, especially important for FullTopic which contains % and /
|
||||||
|
from urllib.parse import quote
|
||||||
|
# Convert value to string and URL encode it
|
||||||
|
encoded_value = quote(str(setting_value), safe='')
|
||||||
|
command = f"{setting_name}%20{encoded_value}"
|
||||||
|
|
||||||
|
self.logger.debug(f"{device_name}: Sending command: {command}")
|
||||||
|
|
||||||
result, success = retry_command(
|
result, success = retry_command(
|
||||||
lambda: send_tasmota_command(device_ip, command, timeout=5, logger=self.logger),
|
lambda: send_tasmota_command(device_ip, command, timeout=5, logger=self.logger),
|
||||||
max_attempts=3,
|
max_attempts=3,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user