# Écrire un optimiseur Un optimiseur est un **serveur** qui parle le [protocole](protocole.md) : il répond au handshake, puis à chaque `GetPlan` par un plan à un ou plusieurs créneaux, ou par une abstention. Le langage est libre. Un optimiseur minimal tient en une cinquantaine de lignes de Python. Session minimale, à titre d'illustration (la forme exacte est dans le [contrat](contrat.md)) : ```text → {"jsonrpc":"2.0","id":1,"method":"Handshake","params":{"protocolVersion":"1.1","engine":"etm-powersync-energy-plugin-etm/…"}} ← {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"1.1","name":"mon-optimiseur","planning":false}} → {"jsonrpc":"2.0","id":2,"method":"GetPlan","params":{ …contexte… }} ← {"jsonrpc":"2.0","id":2,"result":{"abstain":true,"reason":"premier calcul en cours"}} ``` Trois points à ne pas manquer : - **une action par charge disponible** dans le créneau en cours, chacune avec son **motif** en texte : sinon le plan entier est refusé ; - **répondre vite** : servir le dernier plan en cache, ou s'abstenir, et calculer en tâche de fond ; - **ne rien aller chercher ailleurs** : tout ce dont l'optimiseur a besoin, prévisions comprises, est dans le contexte. ## L'optimiseur de référence {#reference} Le dépôt du moteur contient un optimiseur de référence libre (GPL-3.0), en Python, bibliothèque standard seule : [`tools/etm-powersync-ref-optimizer/`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/tree/main/tools/etm-powersync-ref-optimizer). Il répond un plan à un créneau qui reproduit la cascade des règles du moteur, en ne lisant que le contexte. Il s'annonce `powersync-optimizer` au handshake. C'est un point de départ pour écrire le sien, et un point de comparaison : il écoute sur le socket local par défaut, ou sur `tcp://` avec un secret partagé lu dans un fichier. Il sait aussi injecter des défauts (abstention, lenteur, plan invalide, majeure différente…) pour tester le repli du moteur. Mode d'emploi : [son `README.md`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/tools/etm-powersync-ref-optimizer/README.md). ## Brancher le moteur sur son optimiseur {#brancher} Trois méthodes JSON-RPC de la box, réservées à l'administrateur, décrites dans [`INTERFACE.md`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/INTERFACE.md) : - `NymeaEnergy.SetOptimizerEndpoint` — où se connecter (`unix:///…` ou `tcp://hôte:port`) ; - `NymeaEnergy.SetOptimizerToken` — le secret partagé, le même que celui de l'optimiseur ; - `NymeaEnergy.GetOptimizerStatus` — l'état de la connexion : optimiseur vivant, stratégie active, nom annoncé, dernier code d'erreur. Sur `tcp://` sans chiffrement, le secret circule en clair sur le réseau local. ## La suite de conformité {#conformite} La suite `etm-powersync-optimizer-conformance` lance **votre** optimiseur et branche dessus le **vrai** moteur, sur des appareils simulés. Elle vérifie, une fonction par point : 1. le handshake est accepté ; 2. chaque `GetPlan` reçoit sa réponse dans le délai du moteur ; 3. la session entière, dans les deux sens, est conforme au contrat embarqué par le moteur, règles de validation comprises ; 4. chaque plan est appliqué : c'est l'optimiseur qui commande ; 5. la boucle de sécurité reste au-dessus : une consigne hors bornes est écrêtée, une surcharge de phase est délestée. Elle ne juge pas la **qualité** des plans. ### La lancer contre son optimiseur Construire le moteur avec ses tests, puis indiquer la commande qui démarre votre serveur ; `{endpoint}` y est remplacé par l'adresse où écouter : ```sh export ETM_POWERSYNC_OPTIMIZER_CMD='exec /chemin/de/mon-optimiseur --listen {endpoint}' export ETM_POWERSYNC_CONFORMANCE_EXPECT=plan # ou abstain ``` Chaque fonction se lance dans son propre processus. La commande complète (isolement réseau recommandé), les autres variables (secret partagé, délai de démarrage…) et la lecture des échecs sont dans le [`README.md` de la suite](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/tests/auto/conformance/README.md). ### Mode attendu : `plan` ou `abstain` {#mode-attendu} `ETM_POWERSYNC_CONFORMANCE_EXPECT` dit à la suite ce que fait votre optimiseur : - **`plan`** (par défaut) : il commande. Chaque cycle doit appliquer son plan. - **`abstain`** : il s'abstient à chaque cycle — c'est permis, et conforme. La suite vérifie alors que le moteur pilote par ses règles à chaque cycle, sans compter d'échec, et que la sécurité tient toujours ; le contrôle d'écrêtage est sauté, faute de consigne à écrêter. Toute autre valeur fait échouer la suite. **Le mode ne se déduit pas du handshake** : `planning` et `capabilities` décrivent la forme des plans, pas le fait d'en produire. Le mode se donne, il ne se devine pas. ## Comparer sur les mêmes entrées {#traces} Le moteur peut enregistrer, sur la box, une trace de chaque cycle (désactivée par défaut, `NymeaEnergy.SetOptimizerTrace`). L'outil `tools/etm-powersync-trace-replay` rejoue ces traces sur un optimiseur candidat et résume les écarts avec le plan enregistré. Les traces restent sur le site.