Tutoriel : créer des lumières plus intelligentes avec un ESP32 et un Chromebook

Longtemps perçu comme limité pour le développement informatique, le Chromebook est capable de faire de grandes choses notamment au travers de son environnement intégré Linux. Et puisque j’aime bien coder dans une certaine mesure, je me suis lancé dans un projet de réalisation d’un objet connecté. Une occasion nouvelle de montrer les capacités du Chromebook sur la partie de programmation informatique. Dans ce guide, nous allons concevoir un système qui détecte la présence dans une pièce pour gérer l’éclairage de son bureau via Home Assistant.

1. La vidéo

Ce tutoriel est accompagné d’une vidéo pour vous montrer concrétement le fonctionnement et les résultats sur ChromeOS :

2. Matériel requis

Voici le matériel nécessaire pour mener à bien ce projet :

  • Outils : un fer à souder (pour des contacts durables) et un câble micro-USB pour se connecter au Chromebook et pour l’alimentation d’ordre général.
  • Ordinateur : un Chromebook (j’ai personnellement utilisé le Lenovo Chromebook Plus 14 qui est le meilleur Chromebook du marché selon moi et qui est en belle promotion au moment où je vous écris) ! C’est quand même l’exercice, mais dans l’absolu, vous pourriez passer par un autre ordinateur, cependant les phases d’installation de l’environnement technique ne seraient pas les mêmes.
  • Serveur Domotique : Home Assistant afin des gérer les appareils connectés au réseau. Pour ma part, Home Assistant est présent sur un Raspberry Pi.

4. Configuration du Chromebook

Pour programmer l’ESP32, nous devons activer l’environnement Linux sous ChromeOS dans un premier temps :

  1. Allez dans les paramètres de votre Chromebook.
  2. Section « A propos de ChromeOS » puis « Environnement de développement Linux ».
  3. Activez l’environnement de développement Linux et attendez que le tout s’installe.
  4. Le terminal s’ouvre automatiquement si je ne m’abuse (autrement l’application est présente dans le lanceur d’applications) et mettez à jour l’environnement Debian :
sudo apt-get update && sudo apt-get upgrade

5. Installation de l’IDE et du firmware

Nous allons utiliser Thonny IDE, un outil simple et efficace pour le MicroPython (parfait pour coder sans grandes complexités).

Installation de Thonny

Dans votre terminal Linux, tapez :

sudo apt install thonny

Préparation de l’environnement Python

Il est recommandé de créer un environnement virtuel pour bien tout isoler mais d’installer également (au sein de cet environnement) esptool qui va permettre de réaliser la connexion avec l’ESP32 :

python3 -m venv devESP32
source devESP32/bin/activate
sudo apt install python3-pip
pip install esptool

Flashage de MicroPython

Maintenant, il va falloir installer MicroPython sur l’ESP32 afin que l’appareil puisse interpréter le code :

  1. Téléchargez le firmware officiel MicroPython pour ESP32 : micropython.org/download.
  2. Branchez votre ESP32 au Chromebook via le câble USB. Une notification ChromeOS apparaîtra et il faudra simplement autoriser la connexion à Linux.
  3. Lancez Thonny IDE en tapant thonny dans le terminal.
  4. Allez ensuite dans « Exécuter > Configurer l’interpréteur. »
  5. Choisissez MicroPython (ESP32).
  6. Cliquez sur le lien (plus bas) « Install of update MicroPython » puis sélectionnez le port où est connecté l’ESP32 ainsi que le fichier téléchargé. Et cliquez sur le bouton « Installer » pour lancer l’installation !

6. Montage électronique

Il faut désormais relier le module PIR à l’ESP32. En s’aidant du breadboard, il faut relier l’alimentation, la terre ainsi que la transmission de données (dans mon cas, j’ai choisi le pin GPIO 19). Voici une image du montage :

Tutoriel : créer un détecteur de présence connecté avec un ESP32 et un Chromebook
Tutoriel : créer un détecteur de présence connecté avec un ESP32 et un Chromebook

7. Détection de mouvement

Avant de connecter l’objet au réseau, nous allons vérifier que le capteur communique bien avec l’ESP32. Il vous suffit de créer un fichier main.py dans Thonny, de coller le code ci-dessous et d’enregistrer le script dans l’ESP32. Ensuite, vous appuyez sur le bouton « Exécuter le script suivant » (qui ressemble à un bouton de lecture) pour constater le comportement sur la console de Thonny.

from machine import Pin
import time

#Récupération de la valeur qui provient du module PIR
pin_test = Pin(19, Pin.IN)

while True:
    
    if pin_test.value() == 1:
        print("Je te vois !")
    else:
        print("Où es-tu ?")
    print("------------")

    time.sleep(0.1)

Globalement, nous recupérons la valeur transmise par le capteur au travers du pin 19. Si il détecte un mouvement, il nous renvoie la valeur « 1 », si il ne détecte rien, il nous renvoie la valeur « 0 ».

8. Les différentes connextions : Wi-Fi, MQTT et Home Assistant

Pour que notre ESP32 puisse pilote les lumières, j’ai choisi de le faire communiquer avec Home Assistant via le protocole MQTT (très léger, basé sur un système de Publication/Abonnement).

  1. Connexion au réseau Wifi : dans un premier temps, on se connecte au réseau Wifi. Il existe une bibliothèque dédiée sur la partie network qui permet d’activer le Wifi sur l’ESP32 et de réaliser des connexions sur le réseau.
  2. MQTT : ensuite, il faut installer l’intégration MQTT sur votre instance Home Assistant en passant par la section des intégrations. Il faut aussi créer une nouvelle personne dans Home Assistant qui sera uniquement utilisé dans le cadre de la communication MQTT (dans la section 9 de cet article, vous avez le code complet).

Pour ce qui est de la logique : l’ESP32 va publier un message « 1 » sur un « topic » (sujet) quand un mouvement est détecté, et « 0 » après un certain délai sans mouvement. Selon la valeur, il faut faire jouer un scénario Home Assistant pour allumer ou éteindre les lumières. Du coup, vous devrez créer des scénarios comme suit :

9. Code Final : le système complet

Voici le code complet, de production. Il inclut une gestion robuste de la reconnexion Wi-Fi et un système de timer pour éviter que la lumière ne s’éteigne dès que vous ne bougez plus pendant une seconde. Tout ce que je vous ai mis en gras sont des variables à modifier dans le cadre de votre contexte (j’ai mis un timer 1800 dans la variable « init-timer » qui correspond à 1800 secondes, soit 30 minutes d’inactivité pour éteindre les lumières).

from machine import Pin
import time
import network
from umqtt.simple import MQTTClient

# --- Variables d'initialisation ---

ssid = 'SSID_WIFI'
password = 'MDP_SSID'
mqtt_broker = "IP_HOME_ASSISTANT"
client_id = "ESP32_PIR_Entree"
topic_pir = "SUJET"
mqtt_user = "USER_MQTT"
mqtt_pass = "MDP_USER_MQTT"

# --- Configuration du matériel ---

pin_test = Pin(19, Pin.IN)
init_timer = 1800
timer = init_timer

# --- Gestion de la connexion Wi-Fi ---

wlan = network.WLAN(network.STA_IF)

def connecter_wifi():
    """Tente de se connecter au Wi-Fi avec réinitialisation en cas d'erreur interne."""
    global wlan
    try:
        if not wlan.isconnected():
            print("Tentative de connexion au réseau Wi-Fi...")
            # On réinitialise l'interface pour vider les erreurs d'état interne
            wlan.active(False)
            time.sleep(0.5)
            wlan.active(True)
            wlan.connect(ssid, password)
            
            # On attend maximum 10 secondes
            tentatives = 0
            while not wlan.isconnected() and tentatives < 10:
                time.sleep(1)
                print(".")
                tentatives += 1
                
        if wlan.isconnected():
            print("Wi-Fi connecté. IP:", wlan.ifconfig()[0])
            return True
        else:
            print("Échec temporaire du Wi-Fi (Timeout).")
            return False
            
    except OSError as e:
        print("Erreur matérielle Wi-Fi détectée:", e)
        # En cas d'Internal State Error, on force l'arrêt pour le prochain essai
        wlan.active(False)
        return False
    except Exception as e:
        print("Erreur inconnue Wi-Fi:", e)
        return False

# --- Gestion de la connexion MQTT ---

client_mqtt = None

def connecter_mqtt():
    """Initialise et connecte le client MQTT."""
    global client_mqtt
    try:
        # On ne tente MQTT que si le Wi-Fi est OK
        if not wlan.isconnected():
            return False
            
        client_mqtt = MQTTClient(client_id, mqtt_broker, user=mqtt_user, password=mqtt_pass, keepalive=60)
        client_mqtt.connect()
        print("Connecté au Broker MQTT Mosquitto")
        return True
    except Exception as e:
        print("Erreur de connexion MQTT:", e)
        client_mqtt = None
        return False

def verifier_connexions():
    """Vérifie le Wi-Fi et le MQTT, et reconnecte sans jamais arrêter le programme."""
    global client_mqtt
    
    # 1. Vérifier Wi-Fi
    try:
        is_conn = wlan.isconnected()
    except:
        is_conn = False # Si isconnected() plante, on considère déconnecté
        
    if not is_conn:
        print("Perte de connexion Wi-Fi !")
        client_mqtt = None # On invalide le client MQTT si le Wi-Fi tombe
        return connecter_wifi()
            
    # 2. Vérifier MQTT
    if client_mqtt is None:
        return connecter_mqtt()
    
    try:
        client_mqtt.ping()
        return True
    except Exception:
        print("Lien MQTT rompu, reconnexion...")
        client_mqtt = None
        return connecter_mqtt()

# --- Initialisation initiale ---

wlan.active(True)
connecter_wifi()
connecter_mqtt()

# --- Boucle principale ---

while True:
    print("------------")
    
    if verifier_connexions():
        try:
            presence = pin_test.value()
            
            if presence == 1:
                print(f"Timer: {timer} // Mouvement détecté !")
                client_mqtt.publish(topic_pir, "1")
                timer = init_timer
            else:
                print(f"Timer: {timer} // Aucun mouvement.")
                if timer == 0:
                    client_mqtt.publish(topic_pir, "0")
                    timer = -1
                elif timer > 0:
                    timer -= 1
                    
        except Exception as e:
            print("Erreur lors de la publication:", e)
            client_mqtt = None 
    else:
        # Si on arrive ici, c'est qu'on est en train de chercher le réseau
        # On ne fait rien, la prochaine itération de la boucle retentera
        print("Système hors ligne. Recherche de signal...")

    time.sleep(1)

Voilà pour tout ! C’était un plaisir de faire ce petit projet et surtout un moyen de démontrer que le développement informatique est bien possible sur Chromebook !

Laissez un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.