DEV Community

Cover image for Receive DB01 Edge Alerts via Webhook Display with MQTT
applekoiot
applekoiot

Posted on

Receive DB01 Edge Alerts via Webhook Display with MQTT

What you will build

You’ll collect DB01 edge events (temperature/humidity thresholds, motion/light, button/fall) through a webhook endpoint, translate them to MQTT topics, and render a simple dashboard (Node‑RED/Grafana or your own app). The pipeline is:

  1. DB01 advertises BLE packets (or gateway sends HTTP).
  2. A tiny Webhook Server parses the event.
  3. The server publishes to an MQTT Broker (e.g., Mosquitto).
  4. A Dashboard subscribes and visualizes alerts in real time.

(Insert the architecture image webhook_mqtt_architecture.png near here.)

Why a webhook + MQTT split?

  • Webhooks are easy to expose publicly (HTTPS + auth) and map cleanly to event semantics.
  • MQTT provides lightweight fan‑out to any number of consumers (dashboards, mobile apps, cloud rules).
  • You decouple ingest (webhook) from consumption (MQTT) and keep each part independently scalable.

Prerequisites

  • A DB01 beacon and a BLE/Wi‑Fi/LTE gateway that can forward sensor/alert data as HTTP.
  • A server/VM (Linux, macOS, or Windows) with Docker or Python/Node runtimes.
  • An MQTT broker (local Mosquitto is fine).
  • Optional: Node‑RED for a quick dashboard.
  • Open ports: 1883 (MQTT), 1880 (Node‑RED), 8080 (webhook) – or adjust in the configs.

Topic & payload design

Create a small, consistent topic schema so alerts and telemetry are easy to route:

assets/{site}/{device_id}/alerts/{alert_type}
assets/{site}/{device_id}/telemetry
Enter fullscreen mode Exit fullscreen mode

Alert payload (JSON):

{
  "device_id": "DB01-ACME-00042",
  "ts": 1733435152,
  "alert": "TEMP_LOW",
  "temp_c": -12.6,
  "threshold": -10.0,
  "humidity": 68.2,
  "rssi": -63
}
Enter fullscreen mode Exit fullscreen mode

Telemetry payload:

{
  "device_id": "DB01-ACME-00042",
  "ts": 1733435152,
  "temp_c": -5.1,
  "humidity": 61.0,
  "light": 12,
  "motion": 0,
  "battery_v": 2.87
}
Enter fullscreen mode Exit fullscreen mode

Option A — Python (FastAPI) webhook → MQTT

# fastapi_webhook.py
from fastapi import FastAPI, Request, HTTPException
import paho.mqtt.client as mqtt
import os, json, time

MQTT_HOST = os.getenv("MQTT_HOST", "localhost")
MQTT_PORT = int(os.getenv("MQTT_PORT", "1883"))
SITE = os.getenv("SITE", "warehouse-12")

app = FastAPI()
mq = mqtt.Client()
mq.connect(MQTT_HOST, MQTT_PORT, 60)

def topic_alert(dev, atype):  # alert topic
    return f"assets/{SITE}/{dev}/alerts/{atype}"

def topic_telemetry(dev):     # telemetry topic
    return f"assets/{SITE}/{dev}/telemetry"

@app.post("/webhook")
async def webhook(req: Request):
    try:
        body = await req.json()
    except Exception:
        raise HTTPException(status_code=400, detail="Bad JSON")

    dev = body.get("device_id") or "unknown"
    now = int(time.time())
    body.setdefault("ts", now)

    if "alert" in body:
        atype = body["alert"]
        mq.publish(topic_alert(dev, atype), json.dumps(body), qos=1, retain=False)
    else:
        mq.publish(topic_telemetry(dev), json.dumps(body), qos=0, retain=False)

    return {"ok": True}
Enter fullscreen mode Exit fullscreen mode

Run it:

pip install fastapi uvicorn paho-mqtt
uvicorn fastapi_webhook:app --host 0.0.0.0 --port 8080
Enter fullscreen mode Exit fullscreen mode

Option B — Node.js (Express) webhook → MQTT

// express_webhook.js
const express = require("express");
const bodyParser = require("body-parser");
const mqtt = require("mqtt");

const MQTT_HOST = process.env.MQTT_HOST || "localhost";
const MQTT_PORT = process.env.MQTT_PORT || 1883;
const SITE = process.env.SITE || "warehouse-12";

const client = mqtt.connect(`mqtt://${MQTT_HOST}:${MQTT_PORT}`);
const app = express();
app.use(bodyParser.json());

function topicAlert(dev, atype) { return `assets/${SITE}/${dev}/alerts/${atype}`; }
function topicTelemetry(dev) { return `assets/${SITE}/${dev}/telemetry`; }

app.post("/webhook", (req, res) => {
  const body = req.body || {};
  const dev = body.device_id || "unknown";
  body.ts = body.ts || Math.floor(Date.now() / 1000);

  if (body.alert) {
    client.publish(topicAlert(dev, body.alert), JSON.stringify(body), { qos: 1 });
  } else {
    client.publish(topicTelemetry(dev), JSON.stringify(body), { qos: 0 });
  }
  res.json({ ok: true });
});

app.listen(8080, () => console.log("Webhook listening on :8080"));
Enter fullscreen mode Exit fullscreen mode

Run it:

npm i express body-parser mqtt
node express_webhook.js
Enter fullscreen mode Exit fullscreen mode

Docker Compose (optional)

version: "3.8"
services:
  broker:
    image: eclipse-mosquitto:2
    ports: ["1883:1883"]
  webhook:
    build: .
    environment:
      - MQTT_HOST=broker
      - SITE=warehouse-12
    ports: ["8080:8080"]
    depends_on: [broker]
  nodered:
    image: nodered/node-red:latest
    ports: ["1880:1880"]
    depends_on: [broker]
Enter fullscreen mode Exit fullscreen mode

Node‑RED dashboard sketch

  1. Add mqtt in nodes for assets/+/+/alerts/# and assets/+/+/telemetry.
  2. Parse JSON with a function node; route by msg.topic.
  3. Connect to ui_chart, ui_text, or a custom template.
  4. Save flow & deploy. You’ll see alerts streaming in near real‑time.

(Insert the payload image mqtt_topic_payload.png in this section.)

Security hardening checklist

  • TLS termination for your webhook (reverse proxy or cloud LB).
  • Sign webhook requests (HMAC header).
  • Per‑tenant MQTT usernames/passwords and topic‑level ACLs.
  • Secrets via env vars or secret manager.
  • Rate‑limit abusive IPs; log rejects.

Troubleshooting

  • Nothing arrives at MQTT → Check webhook logs; verify JSON.
  • Broker refuses connections → Confirm port/credentials.
  • Dashboard shows stale data → Avoid retain for alerts.
  • High CPU → Disable verbose logging; batch telemetry.

Where to learn more

See families and coverage on the EELINK Official Website .

Top comments (0)