Make a Tasmota ESP an OpenApp opener
You have a Tasmota-capable ESP (ESP8266 or ESP32 family) and want it to open a door or gate from OpenApp. Firmware is stock Tasmota. OpenApp supplies MQTT credentials, an explicit GPIO allowlist, and pulse as a generated Backlog — there is no compile farm.
Product setup: Tasmota integration. Public flash page: install Tasmota.
Do not use a Tasmota ESP as the electric lock on a means of egress. See Life safety and egress.
Architecture
Section titled “Architecture”Agent / SDK / Dashboard → OpenApp entity action (switchable.open) → EMQX ON → openapp/tasmota/{device_id}/cmnd/POWER (slot 0) → openapp/tasmota/{device_id}/cmnd/POWER2 (slot 1) → Tasmota PulseTime (and optional cloud OFF)Only GPIOs listed on the device are programmed as relays. Other user pins are set to None in the same Backlog so OpenApp cannot toggle hardware you did not opt in.
One-time setup
Section titled “One-time setup”- Create integration
provider_type=tasmota(empty config). - Create a device with metadata
outputs: an array of{ "gpio", "output_type", "pulse_ms" }.output_typeisrelay|relay_i|ws2812. Legacygpio+output_type+pulse_msstill creates a single output. OpenApp creates one switch entity per output (channel_index0, 1, …). On the same device form, set opening class. Directswitchable.openis rejected with HTTP 409life_safety_class_requireduntil that is set. Usenot_applicablefor an onboard RGB or other non-door; useingress_only(plus commissioning attestation) for a door or gate. See Life safety and egress. GET /devices/{id}/tasmota/provisioning(authenticated) for the Backlog. Do not put that URL on the public internet.- Flash the stock factory binary (dashboard, marketing installer, or tasmota.github.io/install). Chip is auto-detected. USB port access: Connect the board over USB.
- Happy path: Send settings over USB (Web Serial) while USB is still plugged in. Flash does not send those settings. Fallback: paste the command from Troubleshoot into Tasmota Console at
http://device-lan-ip/, orPOST /devices/{id}/tasmota/provision-lanwith{ "device_host": "192.168.x.y" }. Send settings again after you change the GPIO list.
ESP32-C61-DevKitC-1 onboard RGB: GPIO 8, ws2812 as the sole output. ESP32-S3-DevKitC-1 v1.1 (N16R8): GPIO 38, ws2812 (GPIO 48 on hardware v1.0). Do not use the power LED. WS2812 cannot be mixed with relays. ESP8266 factory builds typically bind 8 relays; the schema allows up to 32 for ESP32.
Open the relay
Section titled “Open the relay”SDK
await client.entities.by_id(entity_id).open()const res = await fetch( `${apiBase}/entities/${entityId}/actions/switchable.open`, { method: "POST", headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json", "x-org": orgId, }, body: JSON.stringify({}), },);if (!res.ok) throw new Error(`open failed: ${res.status}`);use openapp_sdk::Client;use serde_json::json;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
client .entities() .invoke_action(entity_id, "open", &json!({})) .await?;httpResp, err := client.EntitiesAPI.ExecuteEntityAction(ctx, entityID, "open"). Body(map[string]interface{}{}). Execute()if err != nil { return err}defer httpResp.Body.Close()HTTP API (curl)
export OPENAPP_API_BASE='https://api.openapp.house/api/v1'export OPENAPP_API_KEY='v1_openapp_YOUR_SECRET'export OPENAPP_ORG_ID='01HORG00000000000000000000'export ENTITY_ID='01HENTITY000000000000000000'
curl -sS -X POST \ -H "Authorization: Bearer ${OPENAPP_API_KEY}" \ -H "Content-Type: application/json" \ -H "X-Org: ${OPENAPP_ORG_ID}" \ -d '{}' \ "${OPENAPP_API_BASE}/entities/${ENTITY_ID}/actions/switchable.open"Payload on the wire is Tasmota ON. Close is OFF. Toggle is TOGGLE. The first GPIO uses cmnd/POWER; later slots use POWER2, POWER3, ….
Agent tips
Section titled “Agent tips”- Rotate with
POST /devices/{id}/tasmota/rotate-credentialsthen re-apply Backlog. - Topic ACL is
openapp/tasmota/{lowercase device id}/#only. - Prefer USB Backlog over leaving Tasmota’s LAN UI open; WebPassword is set in the same Backlog.
- List only pins you intend OpenApp to drive. Changing
outputsdoes not take effect on the board until Backlog is applied again. - Generic MQTT / Home Assistant / ESPHome YAML remain alternatives via the
mqttplugin — they are not this first-party flash path.