Skip to content

IoT: Gateway-targeted uplink, ACK windows, and downlinks

The IoT Client Profile (user-facing: Sensor Profile) is a Client profile for low-power sensors and actuators. Uplinks are addressed or targeted to a Gateway as the logical endpoint for ACK/downlink behavior and may traverse Repeaters on the path. The Gateway is responsible for ACK/downlink semantics (and repeaters forward opaquely per Routing).

LowMesh optimizes battery-powered Sensor Profile devices by letting them estimate when to wake for an ACK after uplink, including downlink data piggybacked on the ACK.

Wire status: See Payloads for TELEMETRY_BASIC (0x03) and PAYLOAD_BODY_V2 (0x04). IOT_UPLINK / IOT_ACK layouts below are design targets; until promoted, keep experiments in vendor payloads or PAYLOAD_BODY_V2 chunks.

Base Profile implementation path (current)

For Base Profile interoperability, simple IoT Clients (Sensor Profile) SHOULD use TELEMETRY_BASIC plus ACK_BASIC (including ackedSessionId) for basic uplink/ack behavior. IOT_UPLINK and IOT_ACK layouts remain design targets until promoted; experiments SHOULD use vendor payloads or PAYLOAD_BODY_V2. This keeps early firmware from depending on unstable IoT wire formats.

Problem statement

In naive mesh stacks, an IoT device must listen for an unknown duration after transmit because:

  • Path length is unknown.
  • Repeaters may queue traffic.
  • Downlink may be larger than uplink.

IoT ACK timing

The mesh layer is a stateless dumb-pipe: repeaters do not maintain distance-vector nextHop tables for third-party traffic. Sensors SHOULD still publish presence, catalog heard infrastructure, and measure paths for policy (gateway pick, ttlRaw / HASH_SIZE ceilings, ACK timing) — but forwarding uses flood and/or strict source routes encoded on the wire (routing block), not predictive RAM routes.

1) Advertise (NODE_ADVERT)

The sensor transmits NODE_ADVERT (0x0A) — see Node identity & advertisement — so peers learn its srcId, name hints, and (for receivers) last-hop RSSI/SNR when they decode the frame.

2) Build a list of repeaters and gateways

While listening, the sensor records NODE_ADVERT frames from peers whose role / capability indicate repeater or gateway (and IOT_ACK_SVC if it will use timed ACKs). For each candidate nodeId32, it keeps direct RSSI/SNR from the PHY decode (same as Neighbor table).

3) Measure paths with RSSI/SNR per hop (optional)

For each candidate gateway G, the sensor MAY issue TRACEROUTE_REQ (0x0D) — see Traceroute & link metrics. Responses inform expected hop count, margins, and duplicate-suppression / listen-window tuning; they do not imply infrastructure holds a shared predictive graph.

If a future or vendor profile implements IOT_UPLINK, it SHOULD set targetGatewayId to the gateway’s nodeId32 (LE uint32, same family as header srcId / dstId). The mesh header dstId SHOULD address that gateway when using unicast; flood MAY be used for discovery or policy-selected bursts.

Relays forward per Routing. Standard Clients in TempRelay use Dynamic Repeater Mode caps — see Device roles — Dynamic Repeater Mode. Sensor Profile Clients do not relay by default.

Set ttlRaw hop budget consistent with measured hops and the HASH_SIZE TTL ceilings in Routing.

5) When ACKs stop — refresh the pipeline (design target — IOT_ACK)

If a future IOT_ACK profile is in use and ACKs are missing after qosClass requests acknowledged service, or after N failed uplinks / T_ack_fail, the sensor SHOULD:

  1. Widen listen / discovery windows and invalidate local path estimates (no mesh-wide routingEpoch requirement — product-defined),
  2. Transmit NODE_ADVERT again,
  3. Re-run TRACEROUTE_REQ (or equivalent) if used,
  4. Reselect targetGatewayId if appropriate,
  5. Resume IOT_UPLINK (if implemented) with updated maxHops / ttlRaw.

The following sections describe design-target IOT_UPLINK / IOT_ACK wire layouts. They are not Base Profile requirements.

LowMesh declares service intent in the uplink (when IOT_UPLINK is implemented):

  • targetGatewayId — which gateway should terminate the service transaction (nodeId32, 4 bytes LE; 0 = “any gateway” when no path catalog exists yet).
  • maxHops — worst-case hop budget the sender is willing to pay for (1–63).

Wildcard gateway ID: targetGatewayId = 0 means “any gateway” — useful before discovery completes; once paths are known, prefer a concrete nodeId32 for tighter ACK timing.

FieldSizeDescription
targetGatewayId4nodeId32; 0 = “any gateway”
maxHops11–63; relays MUST drop if exceeded
qosClass10 best effort, 1 acknowledged service
appPayloadType2e.g. sensor batch
appPayloadNSensor bytes, control registers, etc.

Hop budget semantics

Originator sets ttl = maxHops. Each relay decrements TTL as usual. If a relay on the best path to targetGatewayId would exceed the remaining budget, it does not forward unless flags.OVERRIDE (operator-only) is set.

This yields a predictable upper bound on over-the-air travel time given known per-hop latency statistics.

IOT_ACK payload (0x62) — Design Target

Sent from the gateway (or designated ACK service node) toward the originating device.

FieldSizeDescription
forMessageId2Correlates to uplink messageId (LE uint16)
forSrcId4Originator nodeId32
forSessionId4Originator sessionId
turnaroundEstMs2Estimated ms from uplink rx to ACK tx completion
listenWindowMs2How long originator should stay awake at minimum
downlinkLen2Bytes following
downlinkNConfiguration, OTA command, actuator state

Sleep scheduling formula (informative)

Let:

  • tAir = estimated one-way airtime sum along worst-case path using maxHops.
  • tQueue = estimate from repeaters (may be 0 if unknown).
  • tGuard = guard band for clock error.

Wake at:

tWakeAfterTx = tAir + tQueue + tGuard

Listen for:

tListen = max(listenWindowMs, tDownlinkDecode)

Implementations SHOULD clamp using turnaroundEstMs from the first ACK if the gateway observes actual path behavior.

Many IoT protocols separate ACK and downlink into different transactions. LowMesh combines them so a sleeping node:

  1. Transmits uplink.
  2. Sleeps until predicted window.
  3. Wakes once to receive ACK + downlink in a single radio transaction where possible.

Security (design-target payloads)

  • If implemented, IOT_ACK uses the same AES-256-CCM-4 envelope as other mesh payloads on all channelHash values.
  • channelHash == 0x0000 exposes IoT metadata to any holder of defaultCommunityPsk32not recommended for sensitive actuator control.

Worked example (design target — not Base Profile)

  1. Sensor on channel 5 sends IOT_UPLINK with maxHops = 4, targetGatewayId = G.
  2. Path is 3 hops; TTL reaches G with value 1 remaining.
  3. Gateway computes turnaroundEstMs = 120, listenWindowMs = 80, downlink = 12-byte valve command.
  4. Sensor schedules sleep ~120 ms (plus guards), wakes, receives ACK, closes valve, returns to deep sleep.

LowMeshOS — always open-source mesh protocol documentation