15 Commits

2 changed files with 124 additions and 52 deletions

View File

@@ -258,7 +258,7 @@ struct Gauge {
long homingBackoffSteps = 3800; // Deliberately a touch past full reverse travel. long homingBackoffSteps = 3800; // Deliberately a touch past full reverse travel.
float velocity = 0.0f; float velocity = 0.0f;
float maxSpeed = 5000.0f; float maxSpeed = 4000.0f;
float accel = 6000.0f; float accel = 6000.0f;
float homingSpeed = 500.0f; float homingSpeed = 500.0f;

112
gauge.py
View File

@@ -28,6 +28,16 @@ import gc
from umqtt.robust import MQTTClient from umqtt.robust import MQTTClient
from machine import UART from machine import UART
# Activate WiFi driver before any heavy heap allocation so it can claim its
# contiguous DRAM block before the Python heap fragments the address space.
# Only activate if not already running (e.g. boot.py may have started it).
gc.collect()
_early_wlan = network.WLAN(network.STA_IF)
if not _early_wlan.active():
_early_wlan.active(True)
del _early_wlan
gc.collect()
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Logging # Logging
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -524,32 +534,56 @@ _DEVICE = {
_wifi_check_interval_ms = 30000 _wifi_check_interval_ms = 30000
_last_wifi_check = 0 _last_wifi_check = 0
_wifi_sta = None _wifi_sta = None
_WIFI_CONNECT_ATTEMPTS = 3
def connect_wifi(ssid, password, timeout_s=15): def _reset_wifi_interface():
global _wifi_sta global _wifi_sta
_wifi_sta = network.WLAN(network.STA_IF) _wifi_sta = network.WLAN(network.STA_IF)
if _wifi_sta.active():
_wifi_sta.active(False)
utime.sleep_ms(200)
_wifi_sta.active(True) _wifi_sta.active(True)
if _wifi_sta.isconnected(): utime.sleep_ms(500)
def connect_wifi(ssid, password, timeout_s=15, force_reconnect=False):
global _wifi_sta
_wifi_sta = network.WLAN(network.STA_IF)
if _wifi_sta.isconnected() and not force_reconnect:
ip, mask, gw, dns = _wifi_sta.ifconfig() ip, mask, gw, dns = _wifi_sta.ifconfig()
info("WiFi already connected") info("WiFi already connected")
info(f" IP:{ip} mask:{mask} gw:{gw} dns:{dns}") info(f" IP:{ip} mask:{mask} gw:{gw} dns:{dns}")
utime.sleep_ms(250)
return ip return ip
info(f"WiFi connecting to '{ssid}' ...")
last_error = None
for attempt in range(_WIFI_CONNECT_ATTEMPTS):
info(f"WiFi connecting to '{ssid}' (attempt {attempt + 1}/{_WIFI_CONNECT_ATTEMPTS}) ...")
_reset_wifi_interface()
try:
_wifi_sta.connect(ssid, password) _wifi_sta.connect(ssid, password)
deadline = utime.time() + timeout_s deadline = utime.time() + timeout_s
while not _wifi_sta.isconnected(): while not _wifi_sta.isconnected():
if utime.time() > deadline: if utime.time() > deadline:
log_err(f"WiFi connect timeout after {timeout_s}s")
raise OSError("WiFi connect timeout") raise OSError("WiFi connect timeout")
utime.sleep_ms(200) utime.sleep_ms(250)
ip, mask, gw, dns = _wifi_sta.ifconfig() ip, mask, gw, dns = _wifi_sta.ifconfig()
mac = ":".join(f"{b:02x}" for b in _wifi_sta.config("mac")) mac = ":".join(f"{b:02x}" for b in _wifi_sta.config("mac"))
info("WiFi connected!") info("WiFi connected!")
info(f" SSID : {ssid}") info(f" SSID : {ssid}")
info(f" MAC : {mac}") info(f" MAC : {mac}")
info(f" IP : {ip} mask:{mask} gw:{gw} dns:{dns}") info(f" IP : {ip} mask:{mask} gw:{gw} dns:{dns}")
utime.sleep_ms(500)
return ip return ip
except Exception as e:
last_error = e
log_err(f"WiFi connect attempt {attempt + 1} failed: {e}")
utime.sleep_ms(1000)
raise last_error
def check_wifi(): def check_wifi():
@@ -567,15 +601,7 @@ def check_wifi():
log_err("WiFi lost connection — attempting reconnect...") log_err("WiFi lost connection — attempting reconnect...")
try: try:
_wifi_sta.active(True) ip = connect_wifi(WIFI_SSID, WIFI_PASSWORD, timeout_s=15, force_reconnect=True)
_wifi_sta.connect(WIFI_SSID, WIFI_PASSWORD)
deadline = utime.time() + 15
while not _wifi_sta.isconnected():
if utime.time() > deadline:
log_err("WiFi reconnect timeout")
return
utime.sleep_ms(200)
ip, mask, gw, dns = _wifi_sta.ifconfig()
info(f"WiFi reconnected! IP:{ip}") info(f"WiFi reconnected! IP:{ip}")
except Exception as e: except Exception as e:
log_err(f"WiFi reconnect failed: {e}") log_err(f"WiFi reconnect failed: {e}")
@@ -858,6 +884,16 @@ def _subscribe_all(c):
def connect_mqtt(): def connect_mqtt():
global client_ref, _mqtt_connected global client_ref, _mqtt_connected
info(f"Connecting to MQTT broker {MQTT_BROKER}:{MQTT_PORT} ...") info(f"Connecting to MQTT broker {MQTT_BROKER}:{MQTT_PORT} ...")
last_error = None
for attempt in range(3):
gc.collect()
try:
if client_ref is not None:
try:
client_ref.disconnect()
except Exception:
pass
client = MQTTClient( client = MQTTClient(
client_id=MQTT_CLIENT_ID, client_id=MQTT_CLIENT_ID,
server=MQTT_BROKER, server=MQTT_BROKER,
@@ -871,6 +907,19 @@ def connect_mqtt():
client_ref = client client_ref = client
_mqtt_connected = True _mqtt_connected = True
info(f"MQTT connected client_id={MQTT_CLIENT_ID}") info(f"MQTT connected client_id={MQTT_CLIENT_ID}")
return
except Exception as e:
last_error = e
log_err(f"MQTT connect attempt {attempt + 1} failed: {type(e).__name__}: {e}")
try:
client.sock.close()
except Exception:
pass
gc.collect()
utime.sleep_ms(1000)
_mqtt_connected = False
raise last_error
_mqtt_check_interval_ms = 30000 _mqtt_check_interval_ms = 30000
@@ -878,7 +927,7 @@ _last_mqtt_check = 0
_discovery_queue = [] _discovery_queue = []
_discovery_idx = 0 _discovery_idx = 0
_last_discovery_ms = 0 _last_discovery_ms = 0
_DISCOVERY_INTERVAL_MS = 200 _DISCOVERY_INTERVAL_MS = 350
def check_mqtt(): def check_mqtt():
@@ -922,6 +971,11 @@ def check_mqtt():
return True return True
except Exception as e2: except Exception as e2:
log_err(f"MQTT reconnect attempt {attempt + 1} failed: {e2}") log_err(f"MQTT reconnect attempt {attempt + 1} failed: {e2}")
try:
client_ref.sock.close()
except Exception:
pass
gc.collect()
utime.sleep_ms(2000) utime.sleep_ms(2000)
log_err("MQTT reconnection failed after 3 attempts") log_err("MQTT reconnection failed after 3 attempts")
@@ -929,6 +983,7 @@ def check_mqtt():
def _publish_discovery_entity(client, topic, payload, log_msg): def _publish_discovery_entity(client, topic, payload, log_msg):
gc.collect()
client.publish(topic, ujson.dumps(payload), retain=True) client.publish(topic, ujson.dumps(payload), retain=True)
info(log_msg) info(log_msg)
@@ -1124,10 +1179,7 @@ def _append_vfd_discovery(entries, dev_ref):
"cmd_t": vfd_topics["set"], "cmd_t": vfd_topics["set"],
"stat_t": vfd_topics["state"], "stat_t": vfd_topics["state"],
"avty_t": gauge_topics[0]["status"], "avty_t": gauge_topics[0]["status"],
"max": 4,
"mode": "text",
"icon": "mdi:alpha-box", "icon": "mdi:alpha-box",
"pattern": "^[0-9A-Fa-f-]{0,4}$",
"dev": dev_ref, "dev": dev_ref,
}, },
"Discovery: VFD text", "Discovery: VFD text",
@@ -1205,14 +1257,17 @@ def service_discovery():
if _last_discovery_ms and utime.ticks_diff(now, _last_discovery_ms) < _DISCOVERY_INTERVAL_MS: if _last_discovery_ms and utime.ticks_diff(now, _last_discovery_ms) < _DISCOVERY_INTERVAL_MS:
return return
gc.collect()
topic, payload, log_msg = _discovery_queue[_discovery_idx] topic, payload, log_msg = _discovery_queue[_discovery_idx]
try:
if isinstance(payload, bytes): if isinstance(payload, bytes):
client_ref.publish(topic, payload, retain=True) client_ref.publish(topic, payload, retain=True)
else: else:
_publish_discovery_entity(client_ref, topic, payload, log_msg) _publish_discovery_entity(client_ref, topic, payload, log_msg)
except Exception as e:
log_err(f"Discovery publish failed for {topic}: {e}")
_discovery_idx += 1 _discovery_idx += 1
_last_discovery_ms = utime.ticks_ms() _last_discovery_ms = utime.ticks_ms()
if (_discovery_idx & 3) == 0:
gc.collect() gc.collect()
@@ -1243,13 +1298,30 @@ def apply_motion_defaults():
def main(): def main():
gc.collect()
info("=" * 48) info("=" * 48)
info("Gauge MQTT controller starting") info("Gauge MQTT controller starting")
info(f"Heap free: {gc.mem_free()} bytes")
info("=" * 48) info("=" * 48)
connect_wifi(WIFI_SSID, WIFI_PASSWORD) gc.collect()
connect_wifi(WIFI_SSID, WIFI_PASSWORD, force_reconnect=True)
mqtt_attempts = 0
while True:
try:
connect_mqtt() connect_mqtt()
break
except Exception as e:
mqtt_attempts += 1
log_err(f"MQTT connect failed: {e} (attempt {mqtt_attempts})")
if mqtt_attempts % 3 == 0:
log_err("WiFi may be stale — forcing reconnect...")
try:
connect_wifi(WIFI_SSID, WIFI_PASSWORD, force_reconnect=True)
except Exception as we:
log_err(f"WiFi reconnect failed: {we}")
utime.sleep_ms(5000)
_subscribe_all(client_ref) _subscribe_all(client_ref)
schedule_discovery() schedule_discovery()