Le watt-proxy est un relais HTTPS sur ESP32-S3 : il exécute à la place des autres modules (en particulier le Guardian TTGO) le handshake TLS qui coûte ~30 KB de heap contigu, en le routant dans sa PSRAM. Il se découvre tout seul par mDNS (SolarMeshLabs._tcp, TXT fonction=proxy) ; son interface web se résume à une page d'état en lecture quasi totale et à un assistant Wi-Fi en mode point d'accès.
Conventions de lecture
Le id est soit l'identifiant HTML de l'élément affiché, soit la clé JSON renvoyée par /state (utile au support). Contrairement aux autres firmwares, le proxy n'a pas de formulaire « à sauvegarder » : la page se rafraîchit toutes les 5 s depuis /state (et en continu via un flux EventSource('/events')). La majorité des champs sont en lecture seule ; seules les cartes « Sécurité » et « Relais cloud » sont éditables et possèdent leur propre bouton d'enregistrement, à effet immédiat.
Badges utilisés dans ce manuel
Immédiat appliqué à chaud, sans redémarrage Reboot redémarre l'appareil opt-in fonction désactivée par défaut
Éléments communs aux deux pages
Le watt-proxy n'a ni barre latérale ni menu : juste un en-tête sobre. La page d'état et l'assistant Wi-Fi partagent l'identité de marque et le sélecteur de langue.
| Élément (id) | Rôle |
|---|---|
| WATT-PROXY + badge d'état — status_badge | Badge vert CONNECTÉ en Wi-Fi, rouge MODE AP en point d'accès (ap_mode), rouge OFFLINE si /state devient injoignable. |
| Sélecteur de langue — lang_select | FR · EN. Charge la préférence via GET /languages puis applique GET /setlanguage?lang= et recharge les libellés à chaud (i18n, sans rechargement de page). Immédiat |
| Repère version — header_meta | Affiche FW<n> · FS<n> (clés fw_build / fs_build). Un badge jaune ⚠ attendu FS= apparaît si le filesystem chargé (fs_build_spiffs) diffère de celui attendu par le firmware — signe d'une mise à jour partielle (reflasher le FS). |
Pas de credentials ? Au démarrage, sans Wi-Fi enregistré, le proxy bascule en point d'accès ouvert WATT-PROXY-xxxx et sert la page Configuration AP. Une fois connecté, c'est la page d'état qui s'affiche.
Page « État » (page principale)
Accès : la racine / en mode Wi-Fi (STA). Une grille de cartes auto-ajustées, toutes alimentées par /state. Description carte par carte.
Carte « Identité »
Lecture seule — qui est l'appareil et où il est sur le réseau.
| Champ (clé /state) | Exemple | Rôle |
|---|---|---|
| Nom — name | Watt-Proxy-58bc | Nom d'hôte mDNS (<name>.local). |
| MAC — mac | A0:B7:65:1C:33:E8 | Adresse matérielle de l'interface Wi-Fi. |
| IP — wifi_ip | 192.168.1.60 | Adresse locale courante ; (AP) en point d'accès. |
| SSID — wifi_ssid | Maison-Wifi | Réseau rejoint. |
| RSSI — rssi | −57 dBm | Force du signal Wi-Fi. |
| Uptime — uptime_s | 4 j 7 h 30 m | Temps depuis le dernier démarrage (formaté côté page). |
Carte « Mémoire »
C'est la raison d'être du proxy : surveiller que la mémoire reste saine pendant les handshakes TLS.
| Champ (clé /state) | Rôle |
|---|---|
| Heap libre — heap_free | RAM interne disponible instantanément. |
| Heap max bloc — heap_max_block | Plus grand bloc contigu allouable — l'indicateur clé pour mbedtls. |
| Heap min historique — heap_min_free | Plancher de heap atteint depuis le boot (détecte les pics de pression). |
| PSRAM libre — psram_free | RAM externe (2–8 MB) où mbedtls route ses gros buffers ; N/A si absente. |
Carte « Statistiques proxy »
Compteurs du trafic proxifié depuis le démarrage. Champs sous stats dans /state.
| Champ (clé) | Rôle |
|---|---|
| Total requêtes — stats.total | Nombre de POST /proxy traités (gros chiffre). |
| Réussies — stats.successful | Requêtes ayant abouti. |
| Échouées — stats.failed | Erreurs HTTPS / timeouts. |
| Dernière (ms) — stats.last_ms | Temps de la dernière requête proxifiée. |
| Sur 60 s — stats.recent_60s | Débit récent, affiché « N/60 » (rate limit global 60 req/min). |
| Dernière erreur — stats.last_error | Dernier message d'échec (cible / code). |
Carte « Cache local (TTL 60 s) »
Cache des réponses idempotentes (ex. Open-Meteo) pour économiser le quota des API et accélérer les requêtes répétées.
| Élément (id / clé) | Type | Rôle |
|---|---|---|
| Entrées valides — cache.entries | lecture | Affiché « entrées / max » (cache.max_entries). |
| Hits / Misses / Évictions — cache.hits / misses / evictions | lecture | Statistiques du cache. |
| Hit ratio — cache.hit_ratio_pct | lecture | Taux de succès en %. La carte n'apparaît que si cache.enabled est vrai. |
| Bouton Vider le cache | bouton | GET /cache/clear (après confirmation) puis rafraîchit. Immédiat |
Carte « Sécurité »
État des protections (lecture) et whitelist de destinations éditable. Champs sous security dans /state.
| Élément (id / clé) | Type | Rôle |
|---|---|---|
| Whitelist destinations — security.whitelist_enabled | lecture | « ✓ Activée » ou « Désactivée ». Si activée, le proxy refuse toute cible hors liste. |
| HMAC Guardian↔Proxy — security.hmac_enabled | lecture | « ✓ Activé » ou « Désactivé (mode compat) ». Signature partagée des requêtes. |
| Hosts par défaut — sec_wl_default ← security.whitelist_default | lecture | Liste figée (un host par ligne) compilée dans le firmware ; non modifiable ici. |
| Hosts custom — sec_wl_extra ← security.whitelist_extra | liste éditable | Vos ajouts, supprimables d'un clic sur « ✕ ». |
| Champ d'ajout — wl_add_in + bouton Ajouter | texte | Valide le format ([a-z0-9.-] + au moins un point) et empile le host en mémoire client. |
| Bouton Enregistrer la whitelist | bouton | POST /setconfig (corps whitelist_extra=<csv>). Immédiat |
Suffixe accepté. « exemple.com » autorise aussi « api.exemple.com ». Les hosts par défaut restent toujours autorisés et ne se modifient pas depuis l'interface.
Carte « Relais cloud (accès distant) »
opt-in Permet de consulter l'état du proxy depuis l'app companion hors du domicile. Lecture seule, chiffré bout-en-bout (AES-256-GCM), zero-knowledge : le serveur ne stocke que des blobs opaques. Désactivé par défaut.
| Élément (id / clé) | Type | Rôle |
|---|---|---|
| Activer le relais cloud — cloud_enabled | case | Active l'envoi périodique de l'instantané chiffré. Désactiver arrête tout envoi. |
| URL du relais — cloud_ingest_url | texte (92) | Worker Cloudflare officiel par défaut ; modifiable si vous hébergez votre propre instance. |
| Clé E2E appairée — cl_claimed ← cloud_claimed | lecture | « Oui » une fois l'app appairée. |
| Envois réussis — cl_count ← cloud_push_count | lecture | Compteur de snapshots transmis. |
| Dernier code — cl_status ← cloud_last_status | lecture | Code HTTP du dernier envoi (« ✓ » si 2xx, « (en attente) » si négatif). |
| Bouton Enregistrer | bouton | GET /setcloud?enabled=&ingest_url=. Immédiat |
| Bouton Tester l'envoi | bouton | GET /cloud/test → {ok, http} ; affiche le code HTTP obtenu. |
Confidentialité. Aucune donnée personnelle dans le snapshot ; l'identifiant est un hash SHA-256 irréversible de la MAC. La clé de chiffrement ne quitte le réseau local qu'au profit de l'app appairée. Code du relais open-source.
Carte « Système »
| Champ (clé /state) | Rôle |
|---|---|
| Boot count — boot_count | Nombre de démarrages cumulés. |
| Dernière cause reset — last_reset | Raison du dernier redémarrage (Power-on, WDT, panic…). |
| Modèle puce — chip_model (+ chip_cores) | Ex. « ESP32-S3 (2 cores) ». |
| SDK — sdk_version | Version ESP-IDF embarquée. |
Carte « Service » & actions
Rappel du rôle (endpoint principal POST /proxy et découverte mDNS) puis les boutons d'action.
| Bouton | Type | Action |
|---|---|---|
| Voir /state JSON | lien | Ouvre /state (le JSON brut qui alimente la page). |
| Voir logs | lien | Ouvre /log — ring buffer texte (128 lignes max). |
| Mettre à jour | bouton | Ouvre la modale OTA (voir ci-dessous). |
| OTA USB | lien | Ouvre /update — téléversement manuel d'un binaire par le navigateur. |
| Redémarrer | bouton | GET /restart après confirmation. Reboot |
| Factory reset | bouton | POST /factoryreset après confirmation : efface la config (Wi-Fi, whitelist, cloud) et redémarre en mode AP. Reboot |
Découverte mDNS. Le proxy publie le service SolarMeshLabs._tcp (port 80) avec le TXT fonction=proxy. Un Guardian dont l'option « proxy auto-discover » est active le détecte et l'utilise sans configuration.
Modale « Mise à jour firmware » (OTA)
Le bouton Mettre à jour ouvre une modale qui interroge le manifest GitHub puis pilote le téléchargement / flash.
| Étape | Endpoint | Rôle |
|---|---|---|
| Préflight | GET /ota/preflight | Conservé pour parité d'API ; le proxy ne se proxifie pas lui-même (stub). |
| Vérification | GET /ota/check | Renvoie state_label = available / uptodate / error, versions, changelog, tailles, need_fw / need_fs. |
| Application | POST /ota/apply | Lance le pipeline (téléchargement + flash + reboot automatique). |
| Suivi | GET /ota/status + SSE /events (ota_status) | Polling 5 s + flux temps réel pendant la barre de progression (countdown 180 s). |
Pendant la mise à jour. Ne pas couper l'alimentation : le redémarrage est automatique. Après coup, vider le cache du navigateur (Ctrl+F5 / Cmd+Shift+R) pour recharger la nouvelle interface.
Page « Configuration AP » (mode point d'accès)
Accès : automatique au premier démarrage (ou après un factory reset), quand aucun Wi-Fi n'est enregistré. Le proxy crée un réseau ouvert WATT-PROXY-xxxx et sert un assistant en une seule étape.
| Champ (id) | Type | Rôle |
|---|---|---|
| Réseau Wi-Fi (SSID) — ssid | texte (requis) | Nom du réseau domestique à rejoindre. |
| Mot de passe — pass | mot de passe | Laisser vide pour un réseau ouvert. |
| Bouton Connecter et redémarrer | bouton | POST /setwifi (FormData ssid + pass) → écrit /wifi.json et redémarre. Reboot |
| Sélecteur de langue — lang_select | liste | FR · EN, comme sur la page d'état. |
L'en-tête affiche FW<n> · MAC (clés fw_build / mac) et le bloc d'aide rappelle le nom mDNS attendu (<name>.local) une fois la connexion établie. Un message vert confirme l'enregistrement ; un message rouge signale l'erreur (SSID manquant, réseau injoignable).
Après connexion. Le proxy quitte le mode AP, rejoint votre réseau, et se retrouve par mDNS (watt-proxy-xxxx.local) ou dans la liste des appareils du routeur. Le Guardian le redécouvre automatiquement.
Annexe — l'endpoint POST /proxy
Le cœur métier n'est pas dans l'interface mais dans cet endpoint, appelé par les autres modules. Il reçoit une requête à exécuter et renvoie la réponse de la cible.
| Sens | Champ | Rôle |
|---|---|---|
| Requête | url | Cible HTTPS (obligatoire). |
| Requête | method · headers · body | Optionnels (défaut GET) ; body utilisé pour POST/PUT. |
| Requête | timeout_ms | Optionnel, défaut 8000, max 30000. |
| Réponse | ok · http_code · body · ms_elapsed | Succès + code HTTP cible + corps brut + durée ; en échec, ok:false + error. |
Pourquoi un proxy ? Ouvrir un handshake TLS coûte ~30 KB de heap contigu — fatal sur un TTGO ESP32 ou un ESP8266. L'ESP32-S3 du proxy route ses buffers mbedtls dans sa PSRAM : le handshake devient quasi gratuit côté heap interne, et les modules « clients » restent stables.