docs: precise SNEK callback config for JSON POST body
- Step-by-step field-by-field callback config table - Common pitfall documented: don't paste JSON body in "Line pattern" - Exact JSON body template format (spaces around colons required) - Companion dashboard deployment steps Backend also cleaned up: unified query-string / JSON body parsing via a single _num() helper instead of nested try/except blocks. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -237,39 +237,65 @@ C'est là que ça devient puissant : à chaque message reçu, SNEK peut faire un
|
|||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
Dans la UI SNEK → onglet **Callbacks** → **Add callback** :
|
### Configurer un callback dans la UI SNEK
|
||||||
- **URL** : `http://mon-service.mon-ns.svc.cluster.local:3000/api/sigfox`
|
|
||||||
- **Method** : POST
|
|
||||||
- **Content-Type** : `application/json`
|
|
||||||
- **Body** : template avec variables SNEK (voir doc SNEK)
|
|
||||||
|
|
||||||
### Exemple de body template
|
Dans SNEK → onglet **Callbacks** → **New** (dans la section DATA callbacks) :
|
||||||
|
|
||||||
|
| Champ | Valeur |
|
||||||
|
|-------|--------|
|
||||||
|
| **Type** | `UPLINK` |
|
||||||
|
| **Channel** | `URL` |
|
||||||
|
| **Send duplicate** | décoché |
|
||||||
|
| **Url pattern** | ton endpoint (ex: `http://mon-service.mon-ns.svc.cluster.local/webhook`) |
|
||||||
|
| **Line pattern** | *(vide)* |
|
||||||
|
| **Content type** | `application/json` |
|
||||||
|
| **Method** *(apparaît selon channel)* | `POST` |
|
||||||
|
| **Body** *(apparaît une fois Method=POST + Content-Type=application/json)* | template JSON ci-dessous |
|
||||||
|
|
||||||
|
Body template (format exact — respecter les espaces autour des `:`) :
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"device": "{device}",
|
"device" : "{device}",
|
||||||
"time": "{time}",
|
"data" : "{data}",
|
||||||
"data": "{data}",
|
"time" : {time},
|
||||||
"rssi": {rssi},
|
"rssi" : {rssi},
|
||||||
"snr": {snr},
|
"snr" : {snr},
|
||||||
"seqNumber": {seqNumber}
|
"seqNumber" : {seqNumber}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Variables disponibles :
|
⚠️ **Piège classique** : ne pas coller le JSON dans **Line pattern**. Ce champ fait une substitution char-par-char et refuse tout ce qui n'est pas un nom de variable connu (tu obtiens `Wrong values. Please fix: ...`). Le body JSON va dans le champ **Body** qui n'apparaît qu'après avoir choisi Method=POST et Content-Type=application/json.
|
||||||
- `{device}` : ID hex du device
|
|
||||||
- `{time}` : timestamp Unix
|
### Variables disponibles
|
||||||
- `{data}` : payload en hex
|
|
||||||
- `{rssi}` : force du signal reçu
|
`{device}` `{time}` `{data}` `{rssi}` `{snr}` `{seqNumber}` `{duplicate}` `{station}` `{avgSnr}` `{LQI}`
|
||||||
- `{snr}` : rapport signal/bruit
|
|
||||||
- `{seqNumber}` : compteur de séquence
|
|
||||||
|
|
||||||
### Cas d'usage
|
### Cas d'usage
|
||||||
|
|
||||||
- **Ingester dans une base** : POST vers une API Node/Go/Python qui insert dans Postgres/InfluxDB
|
- **Dashboard live** : dossier [`dashboard/`](./dashboard/) — Flask + SQLite + SSE + Chart.js prêt à l'emploi
|
||||||
- **Alertes** : POST vers Telegram bot API pour notification instantanée
|
- Ingérer dans une base (Postgres, InfluxDB via une API custom)
|
||||||
- **Bus de messages** : POST vers Kafka REST proxy, RabbitMQ HTTP plugin, etc.
|
- Alertes Telegram / Slack / Discord
|
||||||
- **Dashboard live** : POST vers un WebSocket relay (Socket.io, Server-Sent Events)
|
- Bus de messages Kafka / RabbitMQ
|
||||||
|
|
||||||
|
### Dashboard intégré (companion service)
|
||||||
|
|
||||||
|
Un mini dashboard responsive est fourni dans [`dashboard/`](./dashboard/) — il reçoit les callbacks SNEK, décode les 6 modes Sens'it (Standby, Temperature, Light, Door, Vibration, Magnet), stocke en SQLite et affiche en temps réel via Server-Sent Events. Tailwind + Chart.js.
|
||||||
|
|
||||||
|
Pour le déployer :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd dashboard
|
||||||
|
docker build --platform linux/amd64 -t 192.168.1.100:30500/snek-dashboard:latest .
|
||||||
|
docker push 192.168.1.100:30500/snek-dashboard:latest
|
||||||
|
kubectl apply -f ../deploy/dashboard.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Puis configure le callback SNEK avec l'URL :
|
||||||
|
```
|
||||||
|
http://snek-dashboard.snek.svc.cluster.local/webhook
|
||||||
|
```
|
||||||
|
et le body JSON template ci-dessus. Ouvre `http://<lb-ip-dashboard>` dans un navigateur.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+17
-12
@@ -63,19 +63,24 @@ def index():
|
|||||||
return send_from_directory("static", "index.html")
|
return send_from_directory("static", "index.html")
|
||||||
|
|
||||||
|
|
||||||
@app.route("/webhook", methods=["POST"])
|
def _num(x, cast=float):
|
||||||
|
try:
|
||||||
|
return cast(x)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/webhook", methods=["POST", "GET"])
|
||||||
def webhook():
|
def webhook():
|
||||||
"""
|
"""SNEK callback endpoint. Accepts JSON body OR query string / form params."""
|
||||||
SNEK callback endpoint.
|
src = request.get_json(force=True, silent=True) or request.values
|
||||||
SNEK sends JSON with: device, time, data, rssi, snr, seqNumber, etc.
|
|
||||||
"""
|
device = (src.get("device") or "").lower()
|
||||||
body = request.get_json(force=True, silent=True) or {}
|
raw = (src.get("data") or "").lower()
|
||||||
device = (body.get("device") or "").lower()
|
ts = _num(src.get("time")) or time.time()
|
||||||
raw = (body.get("data") or "").lower()
|
rssi = _num(src.get("rssi"))
|
||||||
ts = float(body.get("time") or time.time())
|
snr = _num(src.get("snr"))
|
||||||
rssi = body.get("rssi")
|
seq_number = _num(src.get("seqNumber") or src.get("seqnumber"), int)
|
||||||
snr = body.get("snr")
|
|
||||||
seq_number = body.get("seqNumber")
|
|
||||||
|
|
||||||
if not device or not raw:
|
if not device or not raw:
|
||||||
return jsonify({"error": "missing device or data"}), 400
|
return jsonify({"error": "missing device or data"}), 400
|
||||||
|
|||||||
Reference in New Issue
Block a user