> ## Documentation Index
> Fetch the complete documentation index at: https://docs.adsumnetworks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# LEW840x gateway firmware specification

> What the Adsum firmware for the Fanstel LEW840x does, in one page: hardware, images, uplink order and failover, BLE scanning, MQTT topics and payloads, the console, configuration and limits.

The reference for the firmware on the [LEW840x](/supported-hardware/fanstel/lew840x) and the [LEW840x with cellular](/supported-hardware/fanstel/lew840x-cellular): what it does, what it publishes, what you can set, and what it does not do yet. Every value on this page is the one the images ship with.

<div className="adsum-byline">
  <span>Gateway <b>Fanstel LEW840F-M2-V3</b></span>
  <span>Built with <b>ESP-IDF 6.0.2 and nRF Connect SDK 3.4.0</b></span>
  <span>Built and verified by <b>Adsum Networks, September 2026</b></span>
</div>

## System

| Element | Part | Role |
| :- | :- | :- |
| **Application host** | ESP32 in the base, 16 MB flash | Runs the gateway: uplinks, MQTT, the console, configuration |
| **Ethernet** | LAN8720A PHY in the base | First uplink by default |
| **Wi-Fi** | The ESP32's own radio | Second uplink |
| **BLE card, M2 slot** | nRF52840 card, with or without a power amplifier | Scans, filters against the whitelist, reports to the ESP32 |
| **Cellular card, LN slot, optional** | nRF9160 card from the LN60G series | LTE-M or NB-IoT, carrying traffic for the ESP32 |

One image reads which cards are fitted at boot. Fitting a cellular card to a unit that had none is a setting and a reboot, and the configuration survives it.

## Firmware images

| Image | Runs on | What it is | How to have it |
| :- | :- | :- | :- |
| **Uplink, two ways out** | ESP32 | Ethernet and Wi-Fi | Free |
| **Uplink, three ways out** | ESP32 | Ethernet, Wi-Fi and cellular | [Free account](/account) |
| **BLE scanner** | nRF52840 card | One image for the amplified card, one for the plain card | Free |
| **Cellular bearer, demo** | nRF9160 card | The modem, carrying traffic, limited use for evaluation | [Free account](/account) |
| **Cellular bearer, production** | nRF9160 card | The same bearer with no limit | Licence, on request |
| **Source** | All three chips | The BLE scanner and the two-way ESP32 application are free; the full source with cellular is licensed | Free, or on request |

Every image comes with a manifest of SHA-256 hashes. The installer checks all of them before it writes any, and a mismatch stops the install with nothing written.

<Warning>
  Flash the BLE image that matches the card. The plain image on an amplified card leaves the amplifier in bypass: no error, just far fewer advertisements heard. The boot log names which image is running.
</Warning>

## Uplinks and failover

| | |
| :- | :- |
| **Order** | Ethernet, then Wi-Fi, then cellular. Set it yourself; it applies live, with no reboot |
| **Carrying** | One uplink at a time. The others stay ready, holding an address |
| **Hold-down** | A link must stay up 5 seconds before traffic moves to it (`failover.holddown_ms`) |
| **Measured failover** | Ethernet cable out to stream resumed on Wi-Fi: 15.4 seconds, read at an independent subscriber |
| **Return** | When a better link comes back, traffic returns to it unprompted |
| **Connectivity watchdog** | With no working uplink for 10 minutes, the gateway restarts itself (`wd.reboot_min`, 0 turns it off) |

## BLE scanning

| | |
| :- | :- |
| **Filtering** | On the BLE card, against a whitelist the ESP32 owns. A device that is not listed never crosses to the ESP32 |
| **Whitelist** | Up to 64 addresses. An empty whitelist observes everything, which is the way to start |
| **Measured** | About 110 advertisements a second received; zero frame errors on the card link over 60 seconds; RSSI of −44 dBm from a tag at arm's length on the amplified card |
| **Card health** | The console shows when the card was last heard from, so a quiet room and a dead radio do not look alike |

## MQTT

| | |
| :- | :- |
| **Broker** | Your host and port (`mqtt.host`, `mqtt.port`, default 1883), with optional user and password |
| **Transport** | Plain TCP in this build |
| **Client id** | Configurable (`mqtt.client_id`) |
| **Keepalive** | 60 seconds (`mqtt.keepalive`) |
| **Topic prefix** | Every topic starts with `mqtt.topic_prefix` |
| **Last will** | `<prefix>/status`, payload `offline`; both configurable |

**Each advertisement**, on Ethernet and Wi-Fi, to `<prefix>/adv`:

```json theme={null}
{ "mac": "D2:14:97:21:15:C9", "type": 1, "rssi": -52, "ts": 815220, "adv": "0201060303aafe" }
```

`type` is the address type, `ts` when the gateway heard it in milliseconds, and `adv` the raw advertisement in hex.

**A digest**, on cellular, to `<prefix>/adv/digest`, one message per interval (60 seconds by default) with one entry per device heard:

```json theme={null}
[{ "mac": "D2:14:97:21:15:C9", "count": 58, "best": -48, "last": -55, "first": 815220, "last_seen": 874910 }]
```

On cellular the gateway sends digests rather than every advertisement, because every byte is billed.

## Cellular data budget

| | |
| :- | :- |
| **Counted** | Only while cellular is carrying. Ethernet and Wi-Fi traffic never counts against it |
| **Cap** | `data.cap_mb`, 50 MB by default |
| **At the cap** | `data.on_exceed`: `sampled` keeps sending digests (the default), `drop` stops publishing |
| **Network** | `lte.network`, LTE-M by default; `lte.roaming` off by default; APN and SIM PIN if your SIM needs them |
| **Standby cost** | A cellular link that carries nothing still spends roughly 4 kB an hour in keepalives |

## The console

Served by the gateway from its own flash, on port 80. No app, no cloud account, nothing to install. It covers the overview, network and uplink order, MQTT, the scanner and whitelist, and status.

| | |
| :- | :- |
| **First power-up** | On a wired network with DHCP: the console is at the address the network gives the gateway. Enter your network, broker and uplink order, then save |
| **A change that strands the unit** | A configuration change must be confirmed. One that is not confirmed within 90 seconds rolls back on its own |
| **Backup** | The configuration exports and imports, from the console or the API |

The same data is available over HTTP to your own tools:

| Endpoint | What |
| :- | :- |
| `GET /api/state` | Uplinks, the broker connection, the scanner, counters |
| `GET /api/config` | The configuration |
| `POST /api/config`, `/commit`, `/confirm`, `/rollback` | Change the configuration, safely |
| `GET /api/config/export`, `POST /api/config/import` | Back up and restore |
| `GET /api/devices` | Devices heard, with RSSI |
| `GET /api/whitelist` | The whitelist |
| `GET /api/transitions` | Recent uplink changes |

## Configuration

| Group | Settings |
| :- | :- |
| **Identity** | `identity.name`, `identity.site` |
| **Ethernet** | `eth.enabled`, `eth.dhcp`, static address, netmask, gateway, two DNS servers |
| **Wi-Fi** | `wifi.enabled`, `wifi.ssid`, `wifi.password`, `wifi.security` (WPA2 by default), DHCP or static |
| **Cellular** | `lte.enabled`, `lte.network`, `lte.apn` with user, password and auth, `lte.sim.pin`, `lte.roaming` |
| **Failover** | `failover.priority`, `failover.holddown_ms` |
| **MQTT** | `mqtt.host`, `mqtt.port`, `mqtt.user`, `mqtt.pass`, `mqtt.client_id`, `mqtt.keepalive`, `mqtt.topic_prefix`, `mqtt.lwt_topic`, `mqtt.lwt_payload` |
| **Data** | `data.cap_mb`, `data.on_exceed` |
| **Time** | `time.ntp` (`pool.ntp.org` by default), `time.timezone` |
| **Watchdog** | `wd.reboot_min` |

Most settings apply live. Network type, roaming and the time server apply on the next reboot. Flashing a new image without erasing keeps the configuration.

## What this build does not do yet

* **No over-the-air updates.** The flash is laid out for them, with two application slots, but there is no update path yet.
* **No TLS to the broker.** The connection is plain TCP. See [CRA readiness](/cra-readiness).
* **No switch between LTE-M and NB-IoT from the console.** It is set on the modem, and the console shows the setting disabled with the reason.
* **No GNSS.** The cellular card carries a GNSS receiver, and this firmware does not use it.
* **The cellular demo is limited.** It is for evaluation; the production bearer has no limit.

<CardGroup cols={2}>
  <Card title="LEW840x: flash it or build it" icon="layer-group" href="/supported-hardware/fanstel/lew840x">
    The gateway, the console, and building it from scratch.
  </Card>

  <Card title="LEW840x with cellular" icon="tower-cell" href="/supported-hardware/fanstel/lew840x-cellular">
    Three ways out, what to order, and the failover walked on the board.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.