Control one or two xTool SafetyPro AP2 air purifiers over BLE and expose them to Home Assistant via an ESP32 (the ap2_hub external component): per-slot fan control with live gear sync, runtime-settable flash-persisted MACs, an on-device scanner, M9033 status polling (filter life, serial, firmware), buzzer control, and BLE bonding. Includes the PC debug tool (tools/ap2_ble.py) and the reverse-engineered protocol spec (SPEC.md). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
28 lines
825 B
Python
28 lines
825 B
Python
import esphome.codegen as cg
|
|
import esphome.config_validation as cv
|
|
from esphome.components import fan
|
|
|
|
from . import AP2Hub, ap2_hub_ns
|
|
|
|
CONF_AP2_HUB_ID = "ap2_hub_id"
|
|
CONF_SLOT = "slot"
|
|
|
|
AP2Fan = ap2_hub_ns.class_("AP2Fan", fan.Fan, cg.Component)
|
|
|
|
CONFIG_SCHEMA = fan.fan_schema(AP2Fan).extend(
|
|
{
|
|
cv.GenerateID(CONF_AP2_HUB_ID): cv.use_id(AP2Hub),
|
|
cv.Required(CONF_SLOT): cv.int_range(min=0, max=1),
|
|
}
|
|
).extend(cv.COMPONENT_SCHEMA)
|
|
|
|
|
|
async def to_code(config):
|
|
var = await fan.new_fan(config)
|
|
await cg.register_component(var, config)
|
|
parent = await cg.get_variable(config[CONF_AP2_HUB_ID])
|
|
cg.add(var.set_hub(parent))
|
|
cg.add(var.set_slot(config[CONF_SLOT]))
|
|
# Let the slot push live gear updates (from M9033) into this fan.
|
|
cg.add(parent.set_fan(config[CONF_SLOT], var))
|