substitutions: device_name: fdm-exhaust-fan-control friendly_name: "FDM Exhaust Fan Control" esphome: name: ${device_name} friendly_name: ${friendly_name} esp32: board: seeed_xiao_esp32c3 framework: type: esp-idf # Enable logging logger: # Enable Home Assistant API api: encryption: key: !secret api_encryption_key ota: - platform: esphome password: !secret ota_password wifi: ssid: !secret wifi_iot_ssid password: !secret wifi_password manual_ip: static_ip: 192.168.69.110 gateway: 192.168.69.1 subnet: 255.255.255.0 ap: ssid: "${friendly_name} Fallback" password: !secret fallback_password # Prevents aggressive reconnection attempts power_save_mode: none # Use 'light' for battery devices # Slower but more reliable connection fast_connect: true # Handle connection failures gracefully on_connect: - logger.log: "Wi-Fi connected!" on_disconnect: - logger.log: "Wi-Fi disconnected!" # Reduce mDNS traffic mdns: disabled: true # Set to true if you use static IPs and don't need discovery captive_portal: web_server: port: 80 # GPIO Outputs for fan control # IMPORTANT: inverted: true because NPN transistor driver inverts the logic # GPIO HIGH -> NPN ON -> Gate LOW -> Fan OFF # GPIO LOW -> NPN OFF -> Gate HIGH (5V via pull-up) -> Fan ON output: - platform: gpio pin: number: GPIO3 # D1 on XIAO inverted: true id: fan_80mm_output - platform: gpio pin: number: GPIO4 # D2 on XIAO inverted: true id: fan_120mm_output # Fan entities for Home Assistant fan: - platform: binary name: "80mm Exhaust Fan" id: fan_80mm output: fan_80mm_output - platform: binary name: "120mm Exhaust Fan" id: fan_120mm output: fan_120mm_output # Optional: Add a switch to control both fans together switch: - platform: template name: "All Fans" id: all_fans turn_on_action: - fan.turn_on: fan_80mm - fan.turn_on: fan_120mm turn_off_action: - fan.turn_off: fan_80mm - fan.turn_off: fan_120mm lambda: |- return id(fan_80mm).state && id(fan_120mm).state; # Diagnostic sensors sensor: - platform: wifi_signal name: "${device_name} WiFi Signal" update_interval: 60s - platform: uptime name: "${device_name} Uptime" update_interval: 60s text_sensor: - platform: wifi_info ip_address: name: "${device_name} IP Address" ssid: name: "${device_name} Connected SSID" bssid: name: "${device_name} BSSID" # Watchdog to auto-reboot if things go wrong interval: - interval: 5min then: - if: condition: and: - lambda: 'return millis() > 300000;' # >5 min uptime - not: wifi.connected: then: - logger.log: "Wi-Fi not connected for 5 min, rebooting..." - delay: 10s - lambda: 'App.safe_reboot();'