Aller au contenu principal
Tutoriels16 min de lecture

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.


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 OpenLaneLink adaptéeArchitecture 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

Composants et coût du système IoTDétail des coûts par composant du système ESP32 + Redis + React

ComposantRôleCoût
ESP32 (x4)Capteurs et actionneurs$40
Raspberry Pi 4Lane computer + Redis$55
Redis (open source)Pub/sub event streaming$0
Node.jsWebSocket server$0
ReactDashboard temps réel$0
Câbles et breadboardConnexions$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
  1. ESP32 capteurs : lisent les valeurs et émettent des events
  2. ESPNow mesh : les nodes communiquent en star-topology
  3. Gateway ESP32 : connectée au Raspberry Pi via UART
  4. Raspberry Pi : Redis reçoit les events, pub/sub les diffuse
  5. Node.js server : WebSocket bridge entre Redis et les clients
  6. 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 pour le système IoTState 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

Comparaison des protocoles IoT : ESPNow vs MQTT vs HTTPRadar comparatif des protocoles IoT : ESPNow, MQTT, HTTP, RS485

CritèreESPNowMQTTHTTPRS485
LatenceTrès faibleFaibleMoyenneFaible
InfrastructureAucuneBroker requisServeur requisCâble
ConsommationTrès faibleFaibleÉlevéeN/A
Portée~200mWiFi rangeWiFi range~1km
Fiabilité RFBonneBonneBonneExcellente
Complexité setupSimpleMoyenneSimpleMoyenne

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

#ESP32#Redis#React#IoT#ESPNow#WebSocket#Temps Réel#2026

Partager cet article

LinkedInX

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.

Passez à l'action avec BOVO Digital

Cet article vous a donné des idées ? Nos experts vous accompagnent de la stratégie à la mise en production.

Articles similaires