ESP32 + Redis + React : construire un système IoT temps réel pour moins de $200 (inspiré OpenLaneLink)
Un SRE a remplacé un système de bowling à $120k par $1,600 d'ESP32. Ce tutoriel s'en inspire pour construire un système IoT temps réel complet : ESPNow mesh, Redis pub/sub, WebSocket, React dashboard. Moins de $200.
ESP32 + Redis + React : construire un système IoT temps réel pour moins de $200 (inspiré OpenLaneLink)
Un SRE a remplacé un système de bowling à $120k par $1,600 d'ESP32. Ce tutoriel s'en inspire pour construire un système IoT temps réel complet, pour moins de $200.
Le 19 juillet 2026, un post Show HN fait sensation : un SRE nommé section33 a remplacé un système de scoring de bowling à $120k par un équivalent basé sur des ESP32 pour $1,600. Le projet, appelé OpenLaneLink, utilise une architecture ESPNow mesh, Redis, et une UI React.
Ce tutoriel s'inspire de cette architecture pour construire un système IoT temps réel générique — capteurs ESP32, event streaming via Redis, dashboard React — pour moins de $200.
L'inspiration : OpenLaneLink
Le défi
Le système de scoring original (2008) coûtait $120k pour 8 pistes de bowling. Il calculait la vitesse de balle, la détection de quilles par caméra, gérait les animations et les machines. Le replacement 1:1 coûtait $80-120k, sans upgrades ni service contracts.
La solution
OpenLaneLink remplace tout par :
- ESP32 avec ESPNow + RS485 fallback : ~$200 par paire de pistes
- Raspberry Pi comme lane computer (Redis + state machine)
- React + WebSocket pour l'UI et les animations
Architecture ESP32 + Redis + React adaptée du projet OpenLaneLink
Le coût total : $1,600 au lieu de $120k, soit 75x moins cher.
L'architecture du système IoT temps réel
Composants
Détail des coûts par composant du système ESP32 + Redis + React
| Composant | Rôle | Coût |
|---|---|---|
| ESP32 (x4) | Capteurs et actionneurs | $40 |
| Raspberry Pi 4 | Lane computer + Redis | $55 |
| Redis (open source) | Pub/sub event streaming | $0 |
| Node.js | WebSocket server | $0 |
| React | Dashboard temps réel | $0 |
| Câbles et breadboard | Connexions | $15 |
| Capteurs (IR, température) | Entrées | $20 |
| Total | ~$130 |
Le pipeline de données
ESP32 → ESPNow mesh → Gateway ESP32 → Raspberry Pi (Redis)
→ WebSocket → React Dashboard
- ESP32 capteurs : lisent les valeurs et émettent des events
- ESPNow mesh : les nodes communiquent en star-topology
- Gateway ESP32 : connectée au Raspberry Pi via UART
- Raspberry Pi : Redis reçoit les events, pub/sub les diffuse
- Node.js server : WebSocket bridge entre Redis et les clients
- React dashboard : affiche les données en temps réel
Étape 1 : Firmware ESP32 (ESPNow)
Configuration ESPNow
// esp32_sensor_node.ino
#include <esp_now.h>
#include <WiFi.h>
typedef struct struct_message {
char node_id[16];
float sensor_value;
unsigned long timestamp;
} struct_message;
struct_message myData;
uint8_t gatewayAddress[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_peer_info_t peerInfo;
memcpy(peerInfo.peer_addr, gatewayAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
Serial.println("Failed to add peer");
return;
}
}
void loop() {
strcpy(myData.node_id, "sensor-01");
myData.sensor_value = readSensor(); // Votre capteur
myData.timestamp = millis();
esp_now_send(gatewayAddress, (uint8_t *)&myData, sizeof(myData));
delay(1000); // 1Hz
}
RS485 fallback
Pour les environnements RF bruyés, ajoutez un fallback câblé RS485 :
// RS485 fallback si ESPNow échoue
if (esp_now_send(...) != ESP_OK) {
sendRS485(myData); // Fallback câblé
}
Étape 2 : Gateway ESP32 → Raspberry Pi
Le gateway ESP32
Le gateway reçoit les events ESPNow et les transmet au Raspberry Pi via UART :
// esp32_gateway.ino
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len) {
memcpy(&myData, incomingData, sizeof(myData));
// Envoyer au Raspberry Pi via UART
Serial.print("EVENT:");
Serial.print(myData.node_id);
Serial.print(",");
Serial.print(myData.sensor_value);
Serial.print(",");
Serial.println(myData.timestamp);
}
Sur le Raspberry Pi : ingestion dans Redis
# ingest.py
import serial
import redis
import json
r = redis.Redis(host='localhost', port=6379, db=0)
ser = serial.Serial('/dev/ttyUSB0', 115200)
while True:
line = ser.readline().decode().strip()
if line.startswith("EVENT:"):
parts = line[6:].split(",")
event = {
"node_id": parts[0],
"sensor_value": float(parts[1]),
"timestamp": int(parts[2])
}
# Publier sur le canal Redis
r.publish('sensor_events', json.dumps(event))
# Stocker le dernier état
r.hset(f"node:{event['node_id']}", "last_value", event['sensor_value'])
Étape 3 : WebSocket bridge (Node.js)
Serveur WebSocket
// server.js
const WebSocket = require('ws');
const redis = require('redis');
const wss = new WebSocket.Server({ port: 8080 });
const redisClient = redis.createClient();
const pubsub = redisClient.duplicate();
// Quand un client se connecte
wss.on('connection', (ws) => {
console.log('Client connected');
});
// Subscribe aux events Redis et broadcast aux WebSocket clients
pubsub.subscribe('sensor_events');
pubsub.on('message', (channel, message) => {
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
});
console.log('WebSocket server running on :8080');
Étape 4 : Dashboard React temps réel
Hook WebSocket personnalisé
// useSensorData.ts
import { useState, useEffect } from 'react';
interface SensorEvent {
node_id: string;
sensor_value: number;
timestamp: number;
}
export function useSensorData(url: string) {
const [events, setEvents] = useState<SensorEvent[]>([]);
const [connected, setConnected] = useState(false);
useEffect(() => {
const ws = new WebSocket(url);
ws.onopen = () => setConnected(true);
ws.onclose = () => setConnected(false);
ws.onmessage = (event) => {
const data: SensorEvent = JSON.parse(event.data);
setEvents(prev => [...prev.slice(-100), data]); // Keep last 100
};
return () => ws.close();
}, [url]);
return { events, connected };
}
Dashboard component
// Dashboard.tsx
import { useSensorData } from './useSensorData';
import { LineChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts';
export function Dashboard() {
const { events, connected } = useSensorData('ws://localhost:8080');
const chartData = events.map(e => ({
time: new Date(e.timestamp).toLocaleTimeString(),
value: e.sensor_value,
node: e.node_id
}));
return (
<div className="p-4">
<div className="flex items-center gap-2 mb-4">
<span className={`h-3 w-3 rounded-full ${connected ? 'bg-green-500' : 'bg-red-500'}`} />
<span className="text-sm">{connected ? 'Connecté' : 'Déconnecté'}</span>
</div>
<ResponsiveContainer width="100%" height={400}>
<LineChart data={chartData}>
<XAxis dataKey="time" />
<YAxis />
<Tooltip />
<Line type="monotone" dataKey="value" stroke="#3B82F6" strokeWidth={2} />
</LineChart>
</ResponsiveContainer>
<div className="mt-4">
<h3>Dernier événement</h3>
<pre>{JSON.stringify(events[events.length - 1], null, 2)}</pre>
</div>
</div>
);
}
Étape 5 : Redis pub/sub et state machine
La state machine
State machine Redis : ingestion, validation, diffusion et alerting
# state_machine.py
import redis
import json
r = redis.Redis(host='localhost', port=6379, db=0)
ALERT_THRESHOLD = 50.0
def process_event(event):
node_id = event['node_id']
value = event['sensor_value']
# 1. Valider
if value < 0 or value > 100:
r.publish('errors', f"Invalid value: {value} from {node_id}")
return
# 2. Stocker l'état
r.hset(f"node:{node_id}", mapping={
"last_value": value,
"last_seen": event['timestamp']
})
# 3. Vérifier les seuils
if value > ALERT_THRESHOLD:
r.publish('alerts', json.dumps({
"node_id": node_id,
"value": value,
"type": "threshold_exceeded"
}))
# 4. Publier pour le dashboard
r.publish('sensor_events', json.dumps(event))
Comparaison des protocoles de communication
Radar comparatif des protocoles IoT : ESPNow, MQTT, HTTP, RS485
| Critère | ESPNow | MQTT | HTTP | RS485 |
|---|---|---|---|---|
| Latence | Très faible | Faible | Moyenne | Faible |
| Infrastructure | Aucune | Broker requis | Serveur requis | Câble |
| Consommation | Très faible | Faible | Élevée | N/A |
| Portée | ~200m | WiFi range | WiFi range | ~1km |
| Fiabilité RF | Bonne | Bonne | Bonne | Excellente |
| Complexité setup | Simple | Moyenne | Simple | Moyenne |
Optimisations production
1. Reconnexion WebSocket avec backoff exponentiel
// Backoff: 1s, 2s, 4s, 8s, 16s, 30s max
const reconnect = () => {
let delay = Math.min(1000 * 2 ** attempts, 30000);
setTimeout(() => connect(), delay);
attempts++;
};
2. Rolling buffer pour éviter la surcharge mémoire
// Garder seulement les 100 derniers événements
setEvents(prev => [...prev.slice(-100), data]);
3. Redis persistence pour les données historiques
# redis.conf
appendonly yes
appendfsync everysec
4. Monitoring avec Redis Insights
# Démarrer RedisInsights pour visualiser les métriques
docker run -d -p 8001:8001 redislabs/redisinsight:latest
Checklist de déploiement
- ESP32 flashés avec firmware ESPNow
- Gateway ESP32 connectée au Raspberry Pi via UART
- Redis installé et démarré sur le Raspberry Pi
- Script d'ingestion Python en cours d'exécution
- Serveur WebSocket Node.js démarré
- Dashboard React buildé et servi
- Test de connectivité ESPNow validé
- RS485 fallback testé (si applicable)
- Reconnexion WebSocket testée (couper/relancer le serveur)
- Monitoring Redis Insights configuré
Conclusion
L'architecture ESP32 + Redis + React, inspirée du projet OpenLaneLink, démontre qu'un système IoT temps réel peut être construit pour moins de $200 — contre les solutions propriétaires à $120k. Les clés du succès : ESPNow pour la communication mesh sans infrastructure, Redis pour le pub/sub sub-millisecond, et React pour un dashboard réactif.
Pour les entreprises qui veulent explorer l'IoT et l'automatisation, notre service de développement web couvre le dashboard React, et notre accompagnement automatisation peut intégrer les données IoT dans vos workflows n8n. Si vous voulez découvrir comment l'IA peut s'intégrer à votre IoT, notre service de création d'agents IA couvre l'analyse temps réel des données capteurs.
Étiquettes
FAQ
Combien coûte un système IoT temps réel basé sur ESP32, Redis et React ?
Le système complet coûte moins de $200 : ~$10 par ESP32, un Raspberry Pi ($35-55) comme lane computer, et le reste pour Redis (gratuit, open source) et React (gratuit). Le projet OpenLaneLink qui inspire ce tutoriel a remplacé un système à $120k par $1,600.
Qu'est-ce que ESPNow et pourquoi l'utiliser pour l'IoT ?
ESPNow est un protocole de communication sans fil d'Espressif qui permet aux ESP32 de communiquer directement entre eux sans routeur WiFi. Il est idéal pour l'IoT car il offre une latence faible, une faible consommation et une topologie mesh.
Pourquoi utiliser Redis dans un système IoT ESP32 ?
Redis est utilisé pour son modèle pub/sub qui permet de diffuser les événements des capteurs vers tous les clients connectés en temps réel. Sa vitesse en mémoire (sub-millisecond) et sa simplicité en font le choix idéal pour l'IoT temps réel.
Quelle est la différence entre MQTT et ESPNow pour les ESP32 ?
MQTT nécessite un broker central et une connexion WiFi, ce qui ajoute de la latence. ESPNow permet une communication directe entre ESP32 sans infrastructure réseau, avec une latence plus faible. RS485 peut être utilisé comme fallback câblé pour les environnements RF bruyés.
Peut-on héberger le dashboard React sur le même Raspberry Pi ?
Oui. Le Raspberry Pi peut faire tourner Redis, le serveur Node.js (WebSocket) et servir le build statique React. Pour la production, il est recommandé de séparer le dashboard sur un serveur plus puissant ou un CDN.
Prêt à l'implémenter ?
Réservez un appel stratégique gratuit de 30 min avec nos experts
Nous analyserons votre situation et proposerons un plan d'action concret.

Singbo Davy AGONMA
Développeur Fullstack & Expert IA. Spécialiste automatisation n8n, développement Laravel/Flutter et intégration d'agents IA. Master CS — IFRI.
