If you manage more than a few ESPHome smart plugs, you’ve probably lived the copy-paste nightmare. 15 device configs that are 90% identical, and when you need to change your WiFi or API key, you’re editing every single one. Then they drift apart over time and nothing’s quite the same anymore.
Hardware absorbs all chip-specific stuff (ESP32 vs ESP8266, GPIO pins, power monitoring chip, LED wiring). Common provides the universal services every device needs (WiFi, OTA, API, uptime, diagnostics).
Function defines what the plug actually does.
The result: a complete device config looks like this:
yaml
substitutions:
device_name: "living-room-lamp"
device_description: "Living room floor lamp - Switchbot miniplug near door"
friendly_name: "Living Room Floor Lamp"
name_no_dashes: "living_room_lamp"
packages:
base: !include common/esp_common.yaml
hardware: !include hardware/switchbot_miniplug_W1901400.yaml
function: !include functions/miniplug_lamp.yaml
That’s the whole file. Compile and flash, you get a light entity in HA with power monitoring, WiFi diagnostics, uptime, connection status LEDs, physical button, OTA, and a web UI.
What’s in it
Two hardware profiles for now that expose the same interface, so any function works on either plug:
| Hardware | Chip | Power Monitoring |
|---|---|---|
| Sonoff S31 | ESP8266 | CSE7766 (UART) |
| SwitchBot Mini Plug W1901400 | ESP32-C3 | BL0937 |
Four function profiles for now:
- Lamp — Simple on/off light entity. That’s it. The baseline.
- Heater — Autonomous freeze protection driven by an HA
input_boolean.freeze_alert. Includes overcurrent detection (immediate relay kill + latching fault) and undercurrent detection (burned out element alert). Physical button clears faults without needing HA. - Timed Light — Flexible scheduling with sunrise, sunset, fixed time, or duration-based on/off. Configurable offsets (e.g., “1 hour before sunrise”). All adjustable from HA at runtime — no reflashing to change schedules.
- Appliance Monitor — Detects running/idle/off states from power draw. Binary mode (one threshold) or Staged mode (two thresholds for multi-state appliances like coffee makers). Fires a “Cycle Complete” sensor you can use to trigger “Dishwasher is done!” notifications. Even multiple level notifications, 1000w drop to 60W “coffee is done” then 60W to <3W “coffee maker turned off, get the last cup”
Everything runs on the plug
One thing I want to emphasize — all the logic lives on the device, not in HA.
The timed light calculates its own sunrise/sunset schedule locally. The heater’s
overcurrent protection kills the relay in 2 seconds flat without waiting for a
network round-trip. The physical button always works. If HA goes down, your
WiFi drops, or your network catches fire, every plug keeps doing its job.
HA is there for configuration and visibility, not as a dependency. The
connection status LED tells you exactly where you stand — and even that
runs locally.
The cross-platform piece
The common base (esp_common.yaml) has zero platform-specific code. The hardware profiles handle all the ESP8266 vs ESP32 differences — different PWM platforms, UART vs GPIO power monitoring, BLE proxy (ESP32 only), the S31’s hardware-coupled relay LED vs the SwitchBot’s software-controlled one. Functions never have to care what chip they’re running on.
Both hardware profiles also implement a consistent connection status LED pattern: fast blink = no WiFi, solid = WiFi but no API, slow sine-wave glow = fully connected.
GitHub
Everything’s documented — each YAML file has a header listing dependencies, provided IDs, and exposed entities. There are docs on the architecture, how to add new hardware, and a substitutions reference.
GitHub: esphome-miniplug-framework
This is a working system I use daily across multiple plugs types.
What’s next?
I’m looking at adding more hardware profiles and possibly extending the pattern beyond smart plugs. But I’d like to hear from you all:
- What other plug hardware should I add profiles for?
- What functions would be useful? (Intermittent device scheduler? Maybe a new function to an existing function profile? Something else?)
PRs welcome if you adapt it for your own hardware.



