An ESP32-WROOM-32 controller for an AMD BC-250 computer powered from a Mean Well LRS-350-12. It provides a real case button and status ring, watches TPMS1, wakes from selected Bluetooth controllers, exposes a local web control panel, and publishes itself to Home Assistant through MQTT Discovery.
Important
This is a soft-power controller. The Mean Well 12 V output remains present whenever its rear rocker is on. The 10-second watchdog reports a failed start but cannot electrically isolate the BC-250.
- Tap while off to start; tap while running to request an OS shutdown.
- Hold five seconds while running to force off, with an eight-second hardware output safety cap.
- TPMS1 analog sensing with averaging, hysteresis, and qualified edges.
- Configurable monitoring for a fan-synchronised external HDD pico-PSU.
- A 10-second startup watchdog and 120-second shutdown watchdog.
- Green ring patterns for off, starting, running, shutdown, setup, and fault.
- Five named BLE or Bluetooth Classic wake bindings.
- A temporary captive setup network opened on first boot or with an eight-second physical hold while off.
- Password-protected, phone-first local dashboard.
- Home Assistant MQTT Discovery, including power, shutdown, force-off, controller wake, state, fault, voltage, Wi-Fi, and diagnostic entities.
The HDD pico-PSU takes its load current from a separately fused Mean Well 12 V branch and uses the BC-250 CPU-fan header only as a low-current on/off signal. The ESP32 does not switch HDD current or delay motherboard startup. The Storage page can report power inferred from board state or confirm it through an optional PC817 connected to the pico-PSU's SATA 5 V output.
Requirements: Node.js 22+, Python 3.11+, and PlatformIO Core.
cd web
npm ci
npm run build
cd ..
pio run -e esp32dev
pio run -e esp32dev -t upload
pio run -e esp32dev -t uploadfsBoth the firmware and LittleFS image must be uploaded. The first boot creates an
open network named BC250 Setup XXXX. Join it and open http://192.168.4.1.
The AP closes after successful router connection or after ten minutes.
Normal access is at http://bc250-xxxx.local or the IP shown by the router.
The stable suffix is derived from the ESP32, while the dashboard display name
can be changed independently.
Run host tests with:
pio test -e nativeRead the complete wiring guide before connecting the board. Compare your inventory with the bill of materials. Do not put mains or BC-250 load current through perfboard or the supplied 18 AWG 5 A fuse holder. Commission the low-voltage controller from USB first.
The dashboard uses authenticated JSON endpoints under /api/v1. Power requests
are serialized by the same state machine used by the physical button and MQTT.
Wi-Fi and MQTT passwords are write-only.
MQTT topics use bc250/<device-id>/...; discovery defaults to homeassistant.
Retained command messages are ignored so reconnecting can never replay a power
action.
| Method | Endpoint | Purpose |
|---|---|---|
GET |
/api/v1/status |
Power, TPMS1, network, MQTT, wake, and reset state |
POST |
/api/v1/power |
on, shutdown, or force_off |
GET/POST |
/api/v1/controllers |
List or bind up to five controllers |
POST |
/api/v1/controllers/scan |
Scan for 15 seconds while the board is off |
DELETE |
/api/v1/controllers/{slot} |
Remove one binding |
GET/PUT |
/api/v1/settings/network |
Read redacted or update network settings |
GET/PUT |
/api/v1/settings/mqtt |
Read redacted or update MQTT settings |
GET/PUT |
/api/v1/settings/storage |
Configure fan-synchronised HDD reporting and optional power sense |
GET |
/api/v1/events |
Recent in-memory events |
POST |
/api/v1/device/restart |
Restart the ESP32 only while safely off |
The UI uses a 10–64 character password, a salted PBKDF2-HMAC-SHA256 hash, eight-hour HttpOnly/SameSite sessions, request-size limits, login backoff, and Host/Origin checks. The setup AP is open and all HTTP and MQTT traffic is unencrypted in v1, so commission nearby and use only a trusted local network.
Enable MQTT on the Home Assistant page and enter the broker host, port,
credentials, and discovery prefix. The default port is 1883 and prefix is
homeassistant; TLS is not included in v1. No YAML or custom component is
needed. Discovery creates operating-state, board-online, TPMS1, fault, wake,
controller, HDD power/source, Wi-Fi, uptime, firmware, reset-reason, controller-wake, power-on,
shutdown, and force-off entities. The retained LWT reports availability;
status changes publish immediately and a complete snapshot repeats every 30
seconds.
The Home Assistant force-off button acts directly and can lose data. Put a confirmation control around it in the HA dashboard if other users have access.
- The Mean Well remains energized while its rocker is on; GPIO16 is reserved for a future properly rated DC cutoff stage.
- Power draw is not estimated from software. GPIO21/22 and API/dashboard space are reserved for a future INA226 plus external shunt.
- Rotating/private BLE addresses cannot be bound. Bluetooth Classic adapter address spoofing is available in Advanced wake settings and takes effect after restarting the controller.
- OTA, cloud access, HTTPS, and MQTT TLS are intentionally out of scope.
The hardware behavior and compatibility research was informed by:
The two unlicensed repositories are behavioral references only; their source is not incorporated. This project is licensed under GPL-3.0-or-later.