Cameleer

Cameleer / Use cases / MQTT edge gateways

Edge and IoT

MQTT edge gateways that keep working when the uplink doesn't

Gateways sit between machines and the cloud. They speak local protocols, keep working offline, and share small hardware with other software. Cameleer runs Apache Camel's routes there without a JVM: five tested patterns, one binary, about 10 MB of memory.

~10 MBmemory for a running route; 8 MB at startup
arm64image for Raspberry Pi 3, 4 and 5 (64-bit), Jetson, Graviton
QoS 0–2MQTT 3.1.1 and 5.0, retained messages, last will, persistent sessions, TLS
0 lostmessages while offline: the buffer is on disk and survives restarts

Five tested patterns

Each is a complete route file in examples/edge/, run by the test suite against the embedded MQTT and Kafka brokers and HTTP mocks. The edge cookbook walks through each one.

patternwhat the route doesfile
Sensor rollupssubscribe to sensors/+/temperature, drop malformed and out-of-range readings, aggregate five readings per sensor (or a minute's worth) into count, min, max and average, publish to Kafka keyed by sensormqtt-sensor-rollup.camel.yaml
Store and forwardtelemetry into a seda queue, post to the cloud with retries and back-off, dead-letter to a buffer folder, replay every 30 seconds and move to .sent on successstore-and-forward.camel.yaml
Syslog to Kafkareceive RFC 5424 and 3164 syslog over UDP, TCP or TLS, parse it, keep warnings and above, publish to Kafkasyslog-to-kafka.camel.yaml
HL7 over MLLPhospital gateway: MLLP in, HTTP to the EHR, acknowledge after delivery (own page)hl7-mllp-to-http.camel.yaml
Gateway presencepublish a retained online status with a last-will offline, plus a heartbeat on a timergateway-heartbeat.camel.yaml

Store and forward, the part that matters

From store-and-forward.camel.yaml: the uplink route's error handler. When the post fails three times, the original message becomes a file in the buffer; a second route replays the buffer.

- route:
    id: uplink
    errorHandler:
      deadLetterChannel:
        deadLetterUri: "file:{{env:BUFFER_DIR:buffer}}?fileName=${date:now:yyyyMMddHHmmssSSS}-${exchangeId}.msg"
        useOriginalMessage: true
        redeliveryPolicy:
          maximumRedeliveries: 3
          redeliveryDelay: "{{env:RETRY_DELAY_MS:1000}}"
          useExponentialBackOff: true
    from:
      uri: "seda:uplink?size=10000"
      steps:
        # ... set headers, post to {{env:UPLINK_URL}}/ingest

Why it holds up

  • The MQTT consumer hands off to a bounded seda queue, so a slow uplink never blocks the broker subscription.
  • useOriginalMessage buffers what arrived, not a half-transformed body.
  • The buffer is a folder: it survives a restart, and it is the only thing the container writes, so the image runs --read-only with one volume.

Components used across the five routes

Footprint on the device

buildbinaryHTTP route readymemory, HTTP route
all components, glibc23.9 MB1.17 ms10.4 MB
--features cloud, static musl11.8 MB0.75 ms5.3 MB
--features core, static musl7.5 MB0.69 ms4.2 MB

Measured on Linux x86-64 with cameleer-bench coldstart; method and the full table in BENCHMARKS. The container image is about 20 MB to download with every component, 12.5 MB with FEATURES=core. For a gateway, --features kafka-mqtt,protocols keeps MQTT, syslog, MLLP and the core; the build features guide lists every family.

Common questions

Does Cameleer run on a Raspberry Pi?

Yes, on a 64-bit OS. The image is published for linux/arm64 (Raspberry Pi 3, 4 and 5 with 64-bit Raspberry Pi OS, NVIDIA Jetson, Graviton) and a running route uses about 10 MB of memory. There is no 32-bit ARM image.

Which MQTT versions and brokers are supported?

paho speaks MQTT 3.1.1 and paho-mqtt5 speaks MQTT 5.0, with QoS 0 to 2, retained messages, last will, persistent sessions and TLS. They are tested against Mosquitto, RabbitMQ and ActiveMQ and work with any broker, including EMQX, HiveMQ and AWS IoT Core.

What happens to messages when the uplink is down?

The store-and-forward route retries with back-off, then writes the original message to a buffer folder through a dead letter channel. A replay route polls the folder every 30 seconds and moves each file to .sent once the cloud accepted it. The buffer is on disk, so it survives restarts.

Can a gateway bridge protocols?

Yes. The tested routes bridge MQTT into Kafka and HTTP, and syslog (RFC 5424 and 3164 over UDP, TCP or TLS) into Kafka with severity filtering. HL7 over MLLP, AMQP, STOMP and files are available on the same gateway.

Is there a Modbus or OPC UA component?

No. Field protocols are expected to arrive through a local broker or an HTTP, TCP or UDP adapter; the netty component handles raw TCP and UDP.

Run it

The buffer is the only thing written, on its own volume; everything else is read-only.

export MQTT_BROKER=tcp://localhost:1883 UPLINK_URL=https://ingest.example.com GATEWAY_ID=plant-7
docker run --rm --network host --read-only -e MQTT_BROKER -e UPLINK_URL -e GATEWAY_ID \
  -e BUFFER_DIR=/buffer -v cameleer-buffer:/buffer -v "$PWD:/routes:ro" \
  pmsudhi/cameleer run /routes/store-and-forward.camel.yaml