EKNOT Access
Production physical access control deployed across 15 residential entrances. Integrates custom ESP32-C6 firmware in C++ with AES-128-CBC challenge-response authentication, optocoupled relay commutation, and an Android administration app in Kotlin and Jetpack Compose.
Signal path
The working path from input to physical or measurable outcome.
Release · diagnostics · deferred lossless synchronisation
Challenge & Requirements
Engineering constraints and goals.
The physical access system required sub-second door unlocks over BLE while maintaining AES-128 cryptographic authentication, reliable power-cycling recovery, and lossless offline logging across 15 access controllers.
Implementation
Architecture and engineering approach.
- 01
Wrote the ESP32-C6 firmware in C++ for authenticated BLE commands, relay control, diagnostics, logs and OTA updates.
- 02
Built the Android service application in Kotlin and Jetpack Compose for discovery, access operations and device administration.
- 03
Implemented an AES-128-CBC challenge-response protocol with role-aware commands and backend-assisted key lookup.
- 04
Prioritised the door-open path while deferring lossless log synchronisation so background work never blocks a person at the entrance.
Hardware Protection & Pinout
Galvanic isolation, flyback suppression & live boot telemetry.
Hardware Pinout & Galvanic Protection Matrix
| Pin / Line | Net Name | Dir | Logic Level | Protection Mechanism | Component | Engineering Rationale |
|---|---|---|---|---|---|---|
GPIO18 | RELAY_ACTUATE | OUT | 3.3V LVTTL -> 12V | Optocoupler Isolation | Everlight EL817 | Galvanically isolates 3.3V ESP32-C6 GPIO from 12V lock strike surges; 5,000 Vrms isolation rating. |
COIL_CLAMP | STRIKE_SNUBBER | PWR | 12V DC Rail | Flyback Snubber Diode | 1N4007 (1kV / 1A) | Shunts inductive kickback (>70V EMF spike) generated when electromagnetic door strike de-energizes. |
GPIO19 | EXIT_BTN_TRIG | IN | 3.3V (10k Pullup) | RC Low-Pass Debounce | 10kΩ + 100nF C0G | Hardware low-pass filter (τ ≈ 1.0 ms) rejects mechanical contact bounce and EMI from long cable runs. |
GPIO20 / 21 | USB_PROV_DP_DM | BUS | 3.3V Full-Speed USB | TVS ESD Array Clamp | USBLC6-2SC6 (SOT-23-6) | Ultra-low capacitance (<3.5pF) TVS diode array clamping ±15kV air / ±8kV contact ESD on provisioning port. |
GPIO22 | STATUS_BEACON | OUT | 3.3V Active-High | Current Limiting Resistor | 330Ω 1% + Green 0805 LED | Limits MCU sink/source current to <7.5mA, preventing GPIO driver thermal stress during long activations. |
VIN / GND_ISO | PWR_5V_REG | PWR | 12V -> 5V / 3.3V DC | Schottky Reverse Polarity | SS34 (40V / 3A) | Blocks accidental reverse polarity insertion from building power supply; star-point digital/actuator GND split. |
ESP-ROM:esp32c6-20220919
Build:Sep 19 2022
rst:0x1 (POWERON),boot:0x2c (SPI_FAST_FLASH_BOOT)
I (28) boot: ESP-IDF v5.2.1-dirty 2nd stage bootloader
I (28) boot: compile time May 14 2026 10:14:22
I (29) boot: chip revision: v0.0
I (33) boot.esp32c6: SPI Speed : 80MHz
I (38) boot.esp32c6: SPI Mode : DIO
I (42) boot.esp32c6: SPI Flash Size : 4MB
I (47) boot: Loaded app partition offset 0x00010000
I (72) cpu_start: Pro cpu up. Frequency: 160MHz
I (88) cpu_start: Starting scheduler on CPU0 (RISC-V RV32IMC)
I (95) main_task: Calling app_main()
I (102) eknot_sys: Initializing EKNOT Access firmware v2.1.4
I (110) heap_init: Initializing. RAM available for dynamic allocation: 498 KB (internal SRAM)
I (125) gpio: GPIO[18]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 1
I (138) eknot_driver: EL817 optocoupler galvanic stage armed on GPIO18
I (145) eknot_filter: Hardware RC debounce (10kΩ/100nF) validated on GPIO19
I (154) esp_ble: BLE 5.3 GATT Server initialized. Service UUID: 0xFFE0, TX Power: +6dBm
I (168) eknot_auth: AES-128-CBC hardware accelerator linked
I (175) eknot_log: Non-volatile ring buffer storage mounted on flash partition
I (190) eknot_main: Hardware initialization completed in 190ms. Listening for BLE clients...
I (2450) eknot_ble: Incoming BLE connection from 64:A2:F9:31:0B:C4 [RSSI: -52 dBm]
I (2472) eknot_auth: Generated 128-bit cryptographic nonce; awaiting client response...
I (2514) eknot_auth: Mutual challenge-response verified OK (HMAC valid, latency: 18ms)
I (2518) eknot_relay: ACTUATE PULSE -> GPIO18 HIGH (800ms) -- [DOOR STRIKE UNLOCKED]
I (3318) eknot_relay: ACTUATE PULSE -> GPIO18 LOW -- [DOOR STRIKE LOCKED]
I (3325) eknot_log: Event #0412 persisted to flash: UNLOCK_SUCCESS [UID: #78291, status: 0x00]Field Evidence
Hardware, wiring and operator interfaces.
HARDWARE / COREESPC6-32 N4 module, 5V optocoupled relay, switching buck regulator and USB-C provisioning interface.
FIELD / WIRING4-PUC-A low-current signal cable routed to door strike relay commutators and 12V rails.
INTERCOM / TERMINALField interface with buzzer (ZUMM), TM touch memory, exit button, status LED and 12V lock actuation lines.
PERIPHERAL / ACTUATORCommutated line terminals (K1, K2) with 12V LED status illumination.
Outcome & Deployment
