Is ESPHome Down? Real-Time Status & Outage Checker
Is ESPHome Down? Real-Time Status & Outage Checker
ESPHome is an open-source system for controlling ESP8266 and ESP32 microcontrollers via declarative YAML configuration, with over 9,000 GitHub stars. Created by Nabu Casa — the company behind Home Assistant — ESPHome compiles custom firmware for sensors, relays, lights, actuators, and hundreds of other components without writing a single line of C++. It supports OTA (over-the-air) updates, a web dashboard at port 6052, native API encryption for direct Home Assistant integration, MQTT, and a growing library of component integrations. ESPHome is the backbone of countless DIY IoT projects: temperature and humidity sensors, motion detectors, smart plugs, LED controllers, and custom Zigbee/BLE proxies. Home automation enthusiasts and professional installers alike rely on ESPHome for fleet-managing dozens or hundreds of embedded devices from a single dashboard.
When ESPHome goes down, the impact is broader than a crashed web app. Devices that rely on the native API lose their connection to Home Assistant, sensor data stops flowing, automations break, and any queued OTA firmware updates stall mid-deployment. A broken Python virtual environment or Docker container OOM kill can silently take the entire compilation pipeline offline while connected devices continue running their last-flashed firmware — until a reboot or config change is required.
Quick Status Check
#!/bin/bash
# ESPHome health check
# Checks dashboard, version endpoint, process, and OTA port
ESPHOME_HOST="${ESPHOME_HOST:-localhost}"
ESPHOME_PORT="${ESPHOME_PORT:-6052}"
OTA_PORT=3232
FAIL=0
echo "=== ESPHome Status Check ==="
echo "Host: ${ESPHOME_HOST}:${ESPHOME_PORT}"
echo ""
# Check version endpoint
VERSION_RESP=$(curl -sf --max-time 5 "http://${ESPHOME_HOST}:${ESPHOME_PORT}/version" 2>&1)
if echo "$VERSION_RESP" | grep -q "version"; then
VERSION=$(echo "$VERSION_RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('version','unknown'))" 2>/dev/null || echo "parse error")
echo "[OK] Version endpoint: ESPHome ${VERSION}"
else
echo "[FAIL] Version endpoint unreachable — dashboard may be down"
FAIL=1
fi
# Check dashboard root (HTML 200)
HTTP_CODE=$(curl -so /dev/null -w "%{http_code}" --max-time 5 "http://${ESPHOME_HOST}:${ESPHOME_PORT}/" 2>/dev/null)
if [ "$HTTP_CODE" = "200" ]; then
echo "[OK] Dashboard root returned HTTP 200"
else
echo "[FAIL] Dashboard root returned HTTP ${HTTP_CODE}"
FAIL=1
fi
# Check ESPHome process
if pgrep -f "esphome" > /dev/null 2>&1; then
echo "[OK] ESPHome process is running"
else
echo "[WARN] ESPHome process not found via pgrep"
fi
# Check port 6052 is listening
if ss -tlnp 2>/dev/null | grep -q ":${ESPHOME_PORT}" || \
netstat -tlnp 2>/dev/null | grep -q ":${ESPHOME_PORT}"; then
echo "[OK] Port ${ESPHOME_PORT} is listening"
else
echo "[FAIL] Port ${ESPHOME_PORT} not listening"
FAIL=1
fi
# Check OTA port 3232 reachable
if nc -z -w 3 "${ESPHOME_HOST}" "${OTA_PORT}" 2>/dev/null; then
echo "[OK] OTA port ${OTA_PORT} is reachable"
else
echo "[WARN] OTA port ${OTA_PORT} not reachable — OTA updates may be blocked"
fi
# Check YAML config directory
CONFIG_DIR="${ESPHOME_CONFIG_DIR:-$HOME/.esphome}"
if [ -d "$CONFIG_DIR" ]; then
YAML_COUNT=$(find "$CONFIG_DIR" -maxdepth 1 -name "*.yaml" 2>/dev/null | wc -l)
echo "[OK] Config directory accessible — ${YAML_COUNT} YAML files found"
else
echo "[WARN] Config directory not found at ${CONFIG_DIR}"
fi
echo ""
if [ "$FAIL" -eq 0 ]; then
echo "Result: ESPHome appears healthy"
else
echo "Result: ESPHome has failures — review output above"
exit 1
fi
Python Health Check
#!/usr/bin/env python3
"""
ESPHome health check
Verifies dashboard, version API, OTA port, and config directory
"""
import json
import os
import socket
import subprocess
import sys
import time
from pathlib import Path
try:
import urllib.request as urlreq
import urllib.error as urlerr
except ImportError:
print("ERROR: urllib not available")
sys.exit(1)
HOST = os.environ.get("ESPHOME_HOST", "localhost")
PORT = int(os.environ.get("ESPHOME_PORT", "6052"))
OTA_PORT = 3232
BASE_URL = f"http://{HOST}:{PORT}"
CONFIG_DIR = Path(os.environ.get("ESPHOME_CONFIG_DIR", Path.home() / ".esphome"))
TIMEOUT = 8
results = []
def check(label, ok, detail=""):
status = "OK" if ok else "FAIL"
msg = f"[{status}] {label}"
if detail:
msg += f" — {detail}"
print(msg)
results.append(ok)
return ok
def fetch(path, timeout=TIMEOUT):
try:
url = f"{BASE_URL}{path}"
req = urlreq.Request(url, headers={"Accept": "application/json,text/html"})
with urlreq.urlopen(req, timeout=timeout) as resp:
return resp.status, resp.read().decode("utf-8", errors="replace")
except urlerr.HTTPError as e:
return e.code, ""
except Exception as e:
return 0, str(e)
print(f"=== ESPHome Python Health Check ===")
print(f"Target: {BASE_URL}")
print()
# 1. Version endpoint
t0 = time.time()
status, body = fetch("/version")
latency = (time.time() - t0) * 1000
if status == 200:
try:
data = json.loads(body)
version = data.get("version", "unknown")
check("Version endpoint", True, f"ESPHome {version} ({latency:.0f}ms)")
except json.JSONDecodeError:
check("Version endpoint", False, "HTTP 200 but body is not valid JSON")
else:
check("Version endpoint", False, f"HTTP {status}")
# 2. Dashboard root (HTML)
status, body = fetch("/")
if status == 200 and ("ESPHome" in body or "esphome" in body or " 3000:
check("Response latency", False, f"{latency:.0f}ms — dashboard may be overloaded")
elif latency > 0:
check("Response latency", True, f"{latency:.0f}ms")
# 4. OTA port 3232
try:
s = socket.create_connection((HOST, OTA_PORT), timeout=3)
s.close()
check("OTA port 3232", True, "reachable")
except (socket.timeout, ConnectionRefusedError, OSError) as e:
check("OTA port 3232", False, f"unreachable ({e}) — OTA firmware updates blocked")
# 5. ESPHome process running
try:
out = subprocess.run(
["pgrep", "-f", "esphome"], capture_output=True, text=True
)
check("ESPHome process", out.returncode == 0,
"running" if out.returncode == 0 else "not found via pgrep")
except FileNotFoundError:
check("ESPHome process", None, "pgrep not available — skipped")
# 6. Config directory and YAML files
if CONFIG_DIR.exists():
yaml_files = list(CONFIG_DIR.glob("*.yaml"))
check("Config directory", True, f"{len(yaml_files)} YAML config(s) at {CONFIG_DIR}")
# Check for recent compilation error markers
build_dir = CONFIG_DIR / ".esphome"
if build_dir.exists():
error_logs = list(build_dir.rglob("compile_error*")) + \
list(build_dir.rglob("*.log"))
if error_logs:
newest = max(error_logs, key=lambda p: p.stat().st_mtime)
age_hours = (time.time() - newest.stat().st_mtime) / 3600
if age_hours < 2:
check("Recent compilation logs", False,
f"Found recent log {newest.name} ({age_hours:.1f}h ago) — check for errors")
else:
check("Recent compilation logs", True, f"Last log {age_hours:.1f}h ago")
else:
check("Config directory", False, f"Not found at {CONFIG_DIR}")
# 7. Python venv check (common breakage point)
venv_paths = [
Path("/srv/esphome/venv"),
Path.home() / ".local/share/esphome/venv",
Path("/opt/esphome/venv"),
]
venv_found = any(p.exists() for p in venv_paths)
if venv_found:
venv = next(p for p in venv_paths if p.exists())
check("Python venv", True, f"Found at {venv}")
else:
check("Python venv", None, "No venv found at common paths — may use system Python")
print()
failures = [r for r in results if r is False]
if not failures:
print("Result: ESPHome appears healthy")
sys.exit(0)
else:
print(f"Result: {len(failures)} check(s) failed — review output above")
sys.exit(1)
Common ESPHome Outage Causes
| Symptom | Likely Cause | Resolution |
|---|---|---|
| Firmware compilation fails with Python errors | Python virtual environment broken after OS or pip upgrade | Recreate the ESPHome venv: pip install --upgrade esphome or reinstall the ESPHome Docker image |
| Docker container crashes or OOM-kills on large configs | Container memory limit too low for YAML configs with many components | Increase Docker memory limit to at least 512 MB; split large YAML configs using packages: includes |
| Home Assistant loses device connections | Native API port (default 6053) blocked by firewall or container network change | Verify port 6053 is open between Home Assistant and ESPHome host; check Docker network mode |
| OTA firmware updates fail or time out | OTA update port 3232 blocked between ESPHome host and device network segment | Ensure port 3232 UDP/TCP is open; check VLAN or IoT network isolation rules |
| Dashboard returns 502 or connection refused | ESPHome process crashed or failed to start after system reboot | Restart ESPHome service or container; check logs for startup errors; verify port 6052 not in use by another process |
| Device fails to compile after ESPHome upgrade | Breaking YAML schema changes in new ESPHome version | Check ESPHome changelog for deprecated keys; run esphome config device.yaml to validate YAML before flashing |
Architecture Overview
| Component | Function | Failure Impact |
|---|---|---|
| Dashboard (port 6052) | Web UI for editing YAML configs, triggering compilations, and viewing device logs | Cannot manage device configurations or initiate OTA updates |
| Compilation Engine | Converts YAML to C++ via ESPHome core, then compiles with PlatformIO/Arduino toolchain | Firmware builds fail; cannot flash new configs to devices |
| Native API Server (port 6053) | Encrypted binary protocol for direct Home Assistant entity discovery and control | Home Assistant loses all ESPHome device entities; automations stop |
| OTA Update Server (port 3232) | Hosts compiled firmware binaries for wireless delivery to ESP devices | Devices cannot receive firmware updates without physical USB flashing |
| MQTT Client (optional) | Publishes sensor values and subscribes to commands via MQTT broker | Devices using MQTT instead of native API stop reporting to home automation |
| Python venv / PlatformIO | Hosts ESPHome Python package, ESP toolchains, and Arduino/ESP-IDF frameworks | All compilation fails; dashboard may still load but cannot build firmware |
Uptime History
| Date | Incident Type | Duration | Impact |
|---|---|---|---|
| 2026-01 | Breaking change in ESPHome 2026.1 YAML schema | Several hours per affected user | Devices using deprecated component keys failed to compile after auto-upgrade |
| 2025-11 | PlatformIO registry outage (external dependency) | ~4 hours | First-time compilations failed; cached builds unaffected |
| 2025-08 | Docker Hub rate limiting during mass pulls | ~2 hours | New ESPHome container deployments failed; existing running containers unaffected |
| 2025-07 | Python 3.12 compatibility regression in ESPHome release | ~6 hours | ESPHome dashboard crashed on startup for users on Python 3.12 systems |
Monitor ESPHome Automatically
ESPHome failures are silent by default — the dashboard can crash overnight and your Home Assistant entities will stop updating while devices continue running their last firmware, giving no obvious error until an automation fails. ezmon.com monitors your ESPHome endpoints from multiple external probes and alerts your team via Slack, PagerDuty, or SMS the moment the dashboard stops responding or the version endpoint returns an unexpected result.