Local Control Endpoint Protocol
This is the SDK’s only local-control protocol: one wire protocol and one service instance serving every local endpoint over a single HTTP server. Local control and challenge-response are independently enable-able endpoint sets on that instance rather than mutually exclusive services, because the endpoints are plain protocomm handlers and protocomm’s HTTP transport is a process-wide singleton. Responses are fragmented so each one fits a small-MTU transport such as BLE GATT.
Variants
local control |
challenge-response |
Behavior |
|---|---|---|
off |
off |
no instance, nothing advertised |
on |
off |
params/config endpoints; |
off |
on |
|
on |
on |
one instance serving both endpoint sets |
Discovery
A single service — _esp_rmaker_ctrl._tcp — is advertised whenever
the instance is up, with the node ID as both the hostname and the service
instance name. TXT records:
Key |
Value |
|---|---|
|
Node ID |
|
Comma-separated active capabilities: |
Clients listing devices filter on cap without connecting (e.g. “available
for control” vs “available for on-network association”). The port is carried
by the mDNS SRV record; the security details are served by the version
endpoint. The cap TXT record is refreshed when endpoint sets are enabled or
disabled.
The service name is fixed at esp_rmaker_ctrl, which is exactly the 15 bytes
RFC 6763 §7.2 allows after the underscore. It carries both endpoint sets
regardless of the name — a node serving only challenge-response advertises the
same service with cap=["ch_resp"].
Session and version endpoints
The service owns its protocomm instance. Session security is protocomm SEC1
(with or without PoP, per ESP_RMAKER_LOCAL_CTRL_SEC1_POP) or SEC2 (SRP6a
with username wifiprov) — Kconfig-selected; security 0 is not supported.
Established on:
rmaker_local_ctrl/session— protocomm session-security endpoint.rmaker_local_ctrl/version— POST any payload; responds with the service info JSON:
{"rmaker_local_ctrl": {"ver": "v1.0", "sec_ver": 2, "sec_patch_ver": 1,
"cap": ["get_params", "set_params", "get_config"]}}
sec_ver / sec_patch_ver are reported by protocomm for the registered
security scheme. cap lists the active endpoint sets (as in the TXT record,
with local control expanded to its endpoint names) and additionally contains
"no_pop" for security 1 without PoP, following the network-provisioning
capability convention.
This endpoint is the authority on capabilities and is rewritten whenever an
endpoint set toggles; the TXT record is only a browse-time filter that may be
absent (BLE, or a client that connected from a QR code without browsing) or
stale. Note the deliberate difference in vocabulary: the TXT record names the
endpoint set (local_ctrl) to stay small, while this endpoint lists the
individual endpoint names a client will call.
Data endpoints
All endpoints inherit the session security:
Endpoint |
Request |
Response |
|---|---|---|
|
protobuf |
protobuf (RespGetData, fragmented) |
|
protobuf |
protobuf (RespGetData, fragmented) |
|
raw JSON (same body as the cloud set-params payload) |
raw JSON: |
Schema: local_ctrl.proto. The endpoint names
and the message/field numbering are the wire contract: treat them as frozen —
changing them breaks deployed clients.
The ch_resp endpoint (challenge-response, used for on-network user-node
association) is registered on the same instance when its endpoint set is
enabled, and appears in cap. A client-issued DisableChalResp command
persists across reboots: the endpoint is removed (after a short delay so
the response is flushed; a ch_resp-only instance is stopped entirely), later
enable attempts are refused, and the state is cleared only by a factory
reset.
Fragmentation (get_params / get_config)
Client-pull, 200-byte fragments:
Client sends
CmdGetData{Offset: 0}— the device (re)generates the full payload and caches it.Response
RespGetData{Status, Buf{Offset, Payload, TotalLen}}carries up to 200 bytes at the requested offset;TotalLenis the full length.Client repeats with
Offset += len(Payload)untilOffset + len(Payload) == TotalLen. The device frees the cache after serving the last fragment.
Notes: a request at offset 0 always regenerates; requests at a non-zero offset
without a prior offset-0 request fail with Fail. There is no per-session
cache — concurrent readers would clobber each other; clients must serialize
their own transfers.
Reserved schema fields
CmdGetData.Timestamp / CmdGetData.HasTimestamp are reserved for a future
signed-response extension and are currently ignored by the device — responses
always carry the raw params/config JSON.
Reference implementations
Firmware:
local_ctrl/(handlers + proto), served bysvc_local_endpoints.c.Client:
local_ctrl.py(LocalController) and the interactivelocal_ctrl_cli/.