# Gateway Rewrite This folder hosts the native ESP-IDF C++ rewrite of the Lua DALI gateway. ## Layout - `apps/`: standard ESP-IDF applications for each firmware role. - `apps/gateway/main/Kconfig.projbuild`: project-visible gateway-role settings such as per-channel native/serial PHY selection, gateway ids, pin mapping, and startup transport policy. - `components/`: reusable components shared by all gateway applications. - `gateway_core/`: boot profile and top-level role bootstrap. - `dali/`: vendored ESP-IDF DALI HAL/backend reused from LuatOS, including native raw receive fan-out. - `dali_domain/`: native DALI domain facade over `dali_cpp` and raw frame sinks. - `gateway_cache/`: DALI scene/group/settings/runtime cache used by controller reconciliation and protocol bridges. - `gateway_bridge/`: per-channel bridge provisioning, command execution, protocol startup, and HTTP bridge actions. - `gateway_modbus/`: gateway-owned Modbus TCP/RTU/ASCII config, generated DALI point tables, and provisioned Modbus model override dispatch. - `gateway_bacnet/`: BACnet/IP server adapter backed by bacnet-stack, including the gateway-owned BACnet bridge model adapter. - `gateway_ble/`: NimBLE GATT bridge for BLE transport parity on `FFF1`/`FFF2`/`FFF3`, including raw DALI notifications. - `gateway_controller/`: Lua-compatible gateway command dispatcher, internal scene/group state, and notification fan-out. - `gateway_network/`: HTTP `/info`, `/dali/cmd`, `/led/1`, `/led/0`, `/jq.js`, UDP port `2020` command/notify routing, Wi-Fi STA lifecycle, ESP-Touch smartconfig, setup AP mode, ESP-NOW setup ingress, and BOOT-button Wi-Fi reset for the native gateway. - `gateway_runtime/`: persistent runtime state, command queueing, and device info services. - `gateway_485_control/`: optional 485 Lua control bridge for framed `0x28 0x01` commands and `0x22 ... checksum` notifications at `9600 8N1`; disabled by default because UART0 must be moved off the ESP-IDF console first. - `gateway_usb_setup/`: optional USB Serial/JTAG setup bridge; disabled by default so USB remains available for debug at boot. ## Current status The native rewrite now wires a shared `gateway_core` bootstrap component, a multi-channel `dali_domain` wrapper over `dali_cpp`, a local vendored `dali` hardware backend from the LuatOS ESP-IDF port with raw receive fan-out, an initial `gateway_runtime` service that provides persistent settings, device info, Lua-compatible command framing helpers, and Lua-style query command deduplication, plus a `gateway_controller` service that starts the gateway command task, dispatches core Lua gateway opcodes, and owns internal scene/group state. The gateway app also includes a `gateway_ble` NimBLE bridge that advertises a Lua-compatible GATT service and forwards `FFF3` framed notifications, incoming `FFF1`/`FFF2`/`FFF3` writes, and native raw DALI frame notifications into the matching raw channel, a `gateway_network` service that provides the native HTTP `/info`, `GET`/`POST /dali/cmd`, `/led/1`, `/led/0`, `/jq.js`, UDP control-plane router on port `2020`, Wi-Fi STA lifecycle, ESP-Touch smartconfig credential provisioning, the Lua-style `LAMMIN_Gateway` setup AP on `192.168.3.1`, ESP-NOW setup ingress for Lua-compatible `connReq`/`connAck`/`echo`/`cmd`/`data`/`uart` packets, native raw DALI frame forwarding back to connected setup peers, and BOOT-button Wi-Fi credential clearing, and an optional `gateway_485_control` bridge that claims UART0 for Lua-compatible framed command ingress plus `0x22` notification egress when the console is moved off UART0. Startup behavior is configured in `main/Kconfig.projbuild`: BLE is enabled by default, Wi-Fi STA, smartconfig, and ESP-NOW setup mode are disabled by default, the built-in USB Serial/JTAG interface stays in debug mode unless the optional USB setup bridge mode is selected, and the UART0 control bridge stays disabled unless the deployment explicitly repurposes UART0 away from the ESP-IDF console. Runtime settings and internal scene/group data are cached in RAM after load, skip unchanged flash writes, and batch Wi-Fi credential commits to reduce flash stalls on ESP32-S3 boards where flash and PSRAM share the SPI bus. The gateway app exposes per-channel PHY selection through `main/Kconfig.projbuild`; each channel can be disabled, bound to the native DALI GPIO HAL, or bound to a UART1/UART2 serial PHY. The checked-in `sdkconfig` is aligned with the app's custom 16 MB partition table so the Wi-Fi/BLE/network-enabled image fits the OTA app slots. ## Modbus Modbus TCP, RTU, and ASCII are owned by `gateway/components/gateway_modbus` and started through the per-channel bridge service. The gateway keeps the existing bridge config JSON shape with a top-level `modbus` object containing `transport`, `host`, `port`, and `unitID`, and now adds nested serial UART settings for RTU/ASCII. Parsing and runtime behavior live in the gateway project rather than in `dali_cpp`. See `MODBUS.md` for transport setup, UART0 policy, RS485 wiring, runtime `@DALIGW` management commands, supported function codes, and the full generated address map with address formulas. The first generated map slice creates stable points for every DALI short address `0-63` whether the device is online, offline, or never seen. Per short address, the generated map reserves a 32-point stride in each Modbus space: - Coils: command triggers such as on, off, recall max, and recall min. - Discrete inputs: inventory, online, supported device-type, cache-known, and base status bit positions. - Holding registers: writable brightness, color temperature, group mask, power-on level, system-failure level, min/max level, and fade time. - Input registers: read-only inventory state, primary type, type mask, cached actual level, scene id, raw status placeholder, group mask, and cached settings. Unknown numeric values read as `0xFFFF`; booleans read as false unless inventory or cache state proves otherwise. Provisioned Modbus models still work as overrides at their configured Modbus point, and normal generated reads prefer gateway cache state to avoid DALI bus polling. An extension discrete-input range starts immediately after the legacy `0-63` short-address block. It publishes decoded DALI status, failure, and feature bits as individual booleans for base status, DT1 emergency, DT4/5/6 control-gear feature/failure status, and DT8 color status/features. This keeps existing Modbus addresses stable while making bit-level diagnostics readable without consumers masking packed status registers. ## BACnet/IP BACnet/IP is owned by `gateway/components/gateway_bacnet` and is started through the per-channel bridge service. Runtime BACnet server settings live under top-level `bacnetServer` in bridge config: ```json { "bacnetServer": { "deviceInstance": 4194303, "localAddress": "", "udpPort": 47808 } } ``` Provisioned BACnet models still use generic `BridgeModel` fields such as object type, object instance, property, and optional `bitIndex`. Query-style models refresh BACnet `Present_Value` from live DALI reads, and binary models with `bitIndex` expose a single packed status bit. For discovered DALI short addresses, the gateway also mirrors the generated Modbus discrete diagnostics as BACnet binary-input objects. Object instances are allocated in a gateway-owned generated range using the channel index plus the generated Modbus discrete-input offset, so generated objects stay deterministic while avoiding the provisioned-object address space in normal deployments.