# main.py — SMQTTS avec certificat client (mTLS)
import ssl, time, json, random, network, esp32
from umqtt.robust import MQTTClient
#----------Load DATA from NVS :-------------------------
# ─── Lecture NVS ─────────────────────────────────────────────
def _nvs_str(nvs, key):
"""Lit une chaîne depuis le NVS. Utilise le retour de get_blob."""
buf = bytearray(128)
try:
n = nvs.get_blob(key, buf) # n = nombre d'octets écrits
return str(buf[:n], "utf-8") # ← buf[:n], jamais buf.index(0)
except OSError:
raise ValueError(f"NVS: clé '{key}' introuvable — avez-vous lancé provision_nvs.py ?")
def load_config():
"""Charge tous les secrets depuis le NVS au démarrage."""
nvs = esp32.NVS("iot_cfg")
return {
"wifi_ssid" : _nvs_str(nvs, "wifi_ssid"),
"wifi_pass" : _nvs_str(nvs, "wifi_pass"),
"broker" : _nvs_str(nvs, "broker"),
"mqtt_user" : _nvs_str(nvs, "mqtt_user"),
"mqtt_pass" : _nvs_str(nvs, "mqtt_pass"),
"mqtt_port" : nvs.get_i32("mqtt_port"),
}
# Chargement unique au démarrage
cfg = load_config()
#-------------------------------------------------------
# ─── Paramètres ─────────────────────────────────────
BROKER = cfg["broker"] # IP VM Debian
PORT = cfg["mqtt_port"] # SMQTTS
CLIENT_ID = "esp32-TEST1" # = CN du certificat
MQTT_USER = cfg["mqtt_user"]
MQTT_PASS = cfg["mqtt_pass"]
#______________________________________________________
TOPIC_DHT = "lab/sensors/dht"
TOPIC_RELAY1 = "lab/action/relay"
TOPIC_RELAY2 = "lab/action/relay2"
WIFI_SSID = cfg["wifi_ssid"]
WIFI_PASSWORD = cfg["wifi_pass"]
# ─── Contexte SSL/TLS mutuel (mTLS) ─────────────────
def build_ssl():
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# Vérification du broker EMQX (CERT_REQUIRED)
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.load_verify_locations("/certs/ca.crt")
# Certificat client — s'identifie auprès d'EMQX (mTLS)
ctx.load_cert_chain("/certs/esp32.crt",
"/certs/esp32.key")
return ctx
# ─── Connexion WiFi ──────────────────────────────────
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print("Connexion WiFi...")
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
while not wlan.isconnected():
pass
print("Connecté WiFi :", wlan.ifconfig())
# ─── Callback messages entrants ─────────────────────
relay1, relay2 = "OFF", "OFF"
def on_msg(topic, msg):
global relay1, relay2
try:
d = json.loads(msg)
etat = d.get("etat","").upper()
if etat not in ("ON","OFF"): return
if topic == TOPIC_RELAY1: relay1 = etat
elif topic == TOPIC_RELAY2: relay2 = etat
print(f"→ Relais: R1={relay1} R2={relay2}")
except Exception as e: print("err:", e)
# ─── Connexion MQTT sécurisée ─────────────────────────
def connect_mqtt():
client = MQTTClient(
CLIENT_ID, BROKER,
port = PORT,
user = MQTT_USER,
password = MQTT_PASS,
ssl = build_ssl(), # ← mTLS
keepalive = 60
)
client.set_last_will(
"lab/status/esp32",
'{"status":"offline"}', retain=True)
client.set_callback(on_msg)
client.connect()
client.subscribe(TOPIC_RELAY1)
client.subscribe(TOPIC_RELAY2)
client.publish("lab/status/esp32",
'{"status":"online"}', retain=True)
print("✓ SMQTTS connecté — port 8883 — mTLS actif")
return client
# ─── Boucle principale ───────────────────────────────
connect_wifi()
mqtt = connect_mqtt()
while True:
try:
t = round(random.uniform(20,40),1)
h = random.randint(30,70)
mqtt.publish(TOPIC_DHT,
json.dumps({"temperature":t,"humidity":h}).encode())
print(f"→ Publié T={t}°C H={h}%")
mqtt.check_msg()
time.sleep(3)
except OSError as e:
print("Reconnexion...", e)
time.sleep(5)
mqtt = connect_mqtt()