diff --git a/docs/faq.en.md b/docs/faq.en.md index 9a47ac3..85bf1e0 100644 --- a/docs/faq.en.md +++ b/docs/faq.en.md @@ -14,11 +14,11 @@ app. That is an architectural decision, not an option. ## Is the project open source? The energy engine (`etm-powersync-energy-plugin-etm`) and the plugins are under -GPL-3.0, including the optimiser client built into the engine — everything linked against -nymea is. The engine works on its own, without an optimiser. The -[protocol between the engine and an optimiser](optimiseur/index.md) is open and -published, with a free reference optimiser and a conformance suite: anyone can write their -own. The **ETM optimiser** and its business logic (tariff arbitration, forecasts learned +GPL-3.0, including the optimizer client built into the engine — everything linked against +nymea is. The engine works on its own, without an optimizer. The +[protocol between the engine and an optimizer](optimiseur/index.md) is open and +published, with a free reference optimizer and a conformance suite: anyone can write their +own. The **ETM optimizer** and its business logic (tariff arbitration, forecasts learned from your installation), however, are proprietary: they run in a separate process, reached through that protocol, at your place — on the box or on a machine in your local network. That process boundary is the heart of the Open Core model — the engine stays free, the diff --git a/docs/fonctionnalites/index.en.md b/docs/fonctionnalites/index.en.md index 20bd031..f74b758 100644 --- a/docs/fonctionnalites/index.en.md +++ b/docs/fonctionnalites/index.en.md @@ -12,7 +12,7 @@ An overview of the HEMS features and their real state. | Baseload forecast | COMING | | [JSON-RPC API](../integrations/jsonrpc-api.md) / [MQTT](../integrations/mqtt.md) | AVAILABLE | | Dynamic tariffs — FR: Tempo, off-peak · DE: §14a EnWG, EPEX spot | ROADMAP | -| CO₂ optimisation — RTE (FR) / SMARD (DE) | ROADMAP | +| CO₂ optimization — RTE (FR) / SMARD (DE) | ROADMAP | | Charge planner | ROADMAP | | Heat pump | ROADMAP | diff --git a/docs/fonctionnalites/moteur.en.md b/docs/fonctionnalites/moteur.en.md index 3a09fc1..d0903d3 100644 --- a/docs/fonctionnalites/moteur.en.md +++ b/docs/fonctionnalites/moteur.en.md @@ -18,7 +18,7 @@ different rates and with different priorities. there is headroom again. It does not wait for the cycle and overrides everything else. - **The allocation cycle, about once a minute.** It shares the available power between the loads. This is the only place a strategy acts: the built-in rules, or an - [optimiser](../optimiseur/index.md) if one is connected. + [optimizer](../optimiseur/index.md) if one is connected. If the grid meter stops answering, the engine suspends allocation and falls back to safety mode: no measurement, no decision. @@ -60,7 +60,7 @@ whatever the strategy: The engine takes no decision without stating why. Every decision carries a non-empty **reason** (`decisionReason`): a stable code and its parameters, which the app displays in your language — "surplus insufficient", "below minimum power", "charging deadline"… The -list of codes is published with the [optimiser protocol](../optimiseur/protocole.md#reponse). +list of codes is published with the [optimizer protocol](../optimiseur/protocole.md#reponse). ## The measurement, never the result of control @@ -75,8 +75,8 @@ enforces safety and answers the app on your local network. Only the edition, any more than the [entered tariff](../tarifs.md): both are displayed and recorded, never used by the rules. -## What about an optimiser? +## What about an optimizer? -An optimiser can propose a plan over several hours, based on the forecasts. It replaces +An optimizer can propose a plan over several hours, based on the forecasts. It replaces the allocation step, **never** the safety loop or the bounds. See the [Optimizer](../optimiseur/index.md) section. diff --git a/docs/fonctionnalites/prevision-pv.en.md b/docs/fonctionnalites/prevision-pv.en.md index 982368b..f86d64f 100644 --- a/docs/fonctionnalites/prevision-pv.en.md +++ b/docs/fonctionnalites/prevision-pv.en.md @@ -71,7 +71,7 @@ therefore neither an "expected error" nor a "confidence interval". ## What the forecast does not do -This is the central rule of the Community edition: **without an optimiser, control is +This is the central rule of the Community edition: **without an optimizer, control is rule-based** (solar surplus, load shedding, priorities). The PV forecast, the [entered tariff](../tarifs.md) and the baseload are **displayed** and **recorded locally**, but never used to decide. An automated test checks this: the engine makes @@ -95,12 +95,12 @@ coordinates** (rounded to about 1 km in the plugin versions that carry this feat tariff and consumption stay on the box. Remote access is disabled by default: it opens only if you enable it yourself in the app. -## What about an optimiser? +## What about an optimizer? -An optimiser, on the other hand, can use these forecasts to plan: the engine hands them +An optimizer, on the other hand, can use these forecasts to plan: the engine hands them over, together with the entered tariff and the baseload, through an -[open, published protocol](../optimiseur/protocole.md). The optimiser runs at your place, +[open, published protocol](../optimiseur/protocole.md). The optimizer runs at your place, on the box or on a machine in your local network, and gets its data from the engine only; -its setpoints stay capped by the engine's bounds and safety. Connecting an optimiser is +its setpoints stay capped by the engine's bounds and safety. Connecting an optimizer is being tested; the Community edition works entirely without one. See the [Optimizer](../optimiseur/index.md) section. diff --git a/docs/index.en.md b/docs/index.en.md index cffffaf..33548e0 100644 --- a/docs/index.en.md +++ b/docs/index.en.md @@ -1,11 +1,11 @@ # ETM PowerSync **Local HEMS for solar PV, heat pump and EV charging installations.** ETM PowerSync -coordinates photovoltaics, battery, heat pump and EV charger under a single optimisation +coordinates photovoltaics, battery, heat pump and EV charger under a single optimization logic — running at your site, on your hardware, with no cloud dependency. Built on [nymea.io](https://nymea.io), following an **Open Core** architecture: a free -foundation (GPL-3.0) and a proprietary optimisation layer. +foundation (GPL-3.0) and a proprietary optimization layer. !!! info "Honest statuses" Every feature shows its real state: STABLE @@ -17,7 +17,7 @@ foundation (GPL-3.0) and a proprietary optimisation layer. - [Installation](installation/index.md) — deploy ETM PowerSync from the APT repository - [Features](fonctionnalites/index.md) — what the HEMS does, and its real state; [how the engine decides](fonctionnalites/moteur.md) -- [Optimizer](optimiseur/index.md) — the open protocol between the engine and an optimiser +- [Optimizer](optimiseur/index.md) — the open protocol between the engine and an optimizer - [Compatibility](appareils/compatibilite.md) — supported equipment - [Integrations](integrations/jsonrpc-api.md) — JSON-RPC API, MQTT, Home Assistant diff --git a/docs/optimiseur/contrat.de.md b/docs/optimiseur/contrat.de.md index cbaa51b..e871c92 100644 --- a/docs/optimiseur/contrat.de.md +++ b/docs/optimiseur/contrat.de.md @@ -42,10 +42,8 @@ Der hier veröffentlichte Vertrag folgt der Entwicklung der Engine; Ihre Box kan die Box: Die JSON-RPC-Methode `NymeaEnergy.GetOptimizerProtocol` liefert den, den sie mitbringt. Dieser ist für einen an diese Box angebundenen Optimierer maßgeblich. -Die Methode ist in -[`INTERFACE.md`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/INTERFACE.md) -im Engine-Repository beschrieben, zusammen mit den übrigen `NymeaEnergy.*`-Methoden des -Optimierers (Verbindungspunkt, gemeinsames Geheimnis, Zustand). Die Verbindung zur API +Sie gehört zu den `NymeaEnergy.*`-Methoden des Optimierers (Verbindungspunkt, gemeinsames +Geheimnis, Zustand); ihre genaue Form liefert die Box selbst über `JSONRPC.Introspect`. Die Verbindung zur API beschreibt die Seite [JSON-RPC-API](../integrations/jsonrpc-api.md). ## Nachrichten prüfen {#valider} diff --git a/docs/optimiseur/contrat.en.md b/docs/optimiseur/contrat.en.md index 39836e2..385f3a3 100644 --- a/docs/optimiseur/contrat.en.md +++ b/docs/optimiseur/contrat.en.md @@ -39,12 +39,10 @@ repository. Its record: The contract published here follows the engine's development; your box may carry an earlier version. To get **the** contract of the installed engine, ask the box: the JSON-RPC method `NymeaEnergy.GetOptimizerProtocol` returns the one it embeds. That is the -one that is authoritative for an optimiser connected to that box. +one that is authoritative for an optimizer connected to that box. -The method is described in -[`INTERFACE.md`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/INTERFACE.md), -in the engine repository, along with the other optimiser `NymeaEnergy.*` methods -(endpoint, shared secret, status). Connecting to the API is described on the +It belongs to the optimizer `NymeaEnergy.*` methods (endpoint, shared secret, status); the +box itself returns their exact form through `JSONRPC.Introspect`. Connecting to the API is described on the [JSON-RPC API](../integrations/jsonrpc-api.md) page. ## Validating messages {#valider} diff --git a/docs/optimiseur/contrat.md b/docs/optimiseur/contrat.md index d7c8295..0663669 100644 --- a/docs/optimiseur/contrat.md +++ b/docs/optimiseur/contrat.md @@ -41,10 +41,8 @@ antérieure. Pour connaître **le** contrat du moteur installé, demandez-le à méthode JSON-RPC `NymeaEnergy.GetOptimizerProtocol` rend celui qu'elle embarque. C'est celui-là qui fait foi pour un optimiseur branché sur cette box. -La méthode est décrite dans -[`INTERFACE.md`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/INTERFACE.md), -dans le dépôt du moteur, avec les autres méthodes `NymeaEnergy.*` de l'optimiseur -(point de connexion, secret partagé, état). La connexion à l'API est décrite sur la page +Elle fait partie des méthodes `NymeaEnergy.*` de l'optimiseur (point de connexion, secret +partagé, état) ; la box en rend la forme exacte par `JSONRPC.Introspect`. La connexion à l'API est décrite sur la page [API JSON-RPC](../integrations/jsonrpc-api.md). ## Valider des messages {#valider} diff --git a/docs/optimiseur/ecrire.de.md b/docs/optimiseur/ecrire.de.md index b928dbb..ef5c828 100644 --- a/docs/optimiseur/ecrire.de.md +++ b/docs/optimiseur/ecrire.de.md @@ -27,7 +27,7 @@ Drei Punkte, die man nicht übersehen sollte: Das Engine-Repository enthält einen freien Referenz-Optimierer (GPL-3.0) in Python, nur mit der Standardbibliothek: -[`tools/etm-powersync-ref-optimizer/`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/tree/main/tools/etm-powersync-ref-optimizer). +[`tools/etm-powersync-ref-optimizer/`](https://git.etm-powersync.fr/ETM-Schurig/etm-powersync-energy-plugin-etm/src/branch/main/tools/etm-powersync-ref-optimizer). Er antwortet mit einem Plan aus einem Zeitfenster, der die Kaskade der Engine-Regeln nachbildet, und liest dabei nur den Kontext. Beim Handshake meldet er sich als `powersync-optimizer`. @@ -36,12 +36,12 @@ Er ist Ausgangspunkt für einen eigenen Optimierer und Vergleichsmaßstab: Er la standardmäßig am lokalen Socket oder an `tcp://` mit einem gemeinsamen Geheimnis, das aus einer Datei gelesen wird. Er kann auch Fehler einspeisen (Enthaltung, Langsamkeit, ungültiger Plan, andere Hauptversion…), um den Rückfall der Engine zu testen. -Anleitung: [seine `README.md`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/tools/etm-powersync-ref-optimizer/README.md). +Anleitung: [seine `README.md`](https://git.etm-powersync.fr/ETM-Schurig/etm-powersync-energy-plugin-etm/src/branch/main/tools/etm-powersync-ref-optimizer/README.md). ## Die Engine an den eigenen Optimierer anbinden {#brancher} -Drei JSON-RPC-Methoden der Box, dem Administrator vorbehalten, beschrieben in -[`INTERFACE.md`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/INTERFACE.md): +Drei JSON-RPC-Methoden der Box (die ersten beiden dem Administrator vorbehalten); ihre genaue +Form liefert die Box selbst über `JSONRPC.Introspect`: - `NymeaEnergy.SetOptimizerEndpoint` — wohin verbinden (`unix:///…` oder `tcp://host:port`); - `NymeaEnergy.SetOptimizerToken` — das gemeinsame Geheimnis, dasselbe wie beim Optimierer; @@ -78,7 +78,7 @@ export ETM_POWERSYNC_CONFORMANCE_EXPECT=plan # oder abstain Jede Funktion läuft in einem eigenen Prozess. Der vollständige Befehl (Netzisolierung empfohlen), die übrigen Variablen (gemeinsames Geheimnis, Startfrist…) und das Lesen der Fehlschläge stehen in der -[`README.md` der Suite](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/tests/auto/conformance/README.md). +[`README.md` der Suite](https://git.etm-powersync.fr/ETM-Schurig/etm-powersync-energy-plugin-etm/src/branch/main/tests/auto/conformance/README.md). ### Erwarteter Modus: `plan` oder `abstain` {#mode-attendu} diff --git a/docs/optimiseur/ecrire.en.md b/docs/optimiseur/ecrire.en.md index dcdda49..a790f8a 100644 --- a/docs/optimiseur/ecrire.en.md +++ b/docs/optimiseur/ecrire.en.md @@ -1,14 +1,14 @@ # Writing an optimizer -An optimiser is a **server** that speaks the [protocol](protocole.md): it answers the +An optimizer is a **server** that speaks the [protocol](protocole.md): it answers the handshake, then every `GetPlan` with a plan of one or more slots, or with an abstention. -Any language will do. A minimal optimiser fits in about fifty lines of Python. +Any language will do. A minimal optimizer fits in about fifty lines of Python. Minimal session, for illustration (the exact shape is in the [contract](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":"my-optimiser","planning":false}} +← {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"1.1","name":"my-optimizer","planning":false}} → {"jsonrpc":"2.0","id":2,"method":"GetPlan","params":{ …context… }} ← {"jsonrpc":"2.0","id":2,"result":{"abstain":true,"reason":"premier calcul en cours"}} ``` @@ -19,14 +19,14 @@ Three things not to miss: text: otherwise the whole plan is rejected (the reason text is in French); - **answer quickly**: serve the last cached plan, or abstain, and compute in the background; -- **fetch nothing elsewhere**: everything the optimiser needs, forecasts included, is in +- **fetch nothing elsewhere**: everything the optimizer needs, forecasts included, is in the context. -## The reference optimiser {#reference} +## The reference optimizer {#reference} -The engine repository contains a free reference optimiser (GPL-3.0), in Python, standard +The engine repository contains a free reference optimizer (GPL-3.0), in Python, standard library only: -[`tools/etm-powersync-ref-optimizer/`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/tree/main/tools/etm-powersync-ref-optimizer). +[`tools/etm-powersync-ref-optimizer/`](https://git.etm-powersync.fr/ETM-Schurig/etm-powersync-energy-plugin-etm/src/branch/main/tools/etm-powersync-ref-optimizer). It answers a one-slot plan that reproduces the cascade of the engine's rules, reading only the context. At handshake it announces itself as `powersync-optimizer`. @@ -34,52 +34,52 @@ It is a starting point for writing your own, and a point of comparison: it liste local socket by default, or on `tcp://` with a shared secret read from a file. It can also inject faults (abstention, slowness, invalid plan, different major version…) to test the engine's fallback. Instructions: -[its `README.md`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/tools/etm-powersync-ref-optimizer/README.md). +[its `README.md`](https://git.etm-powersync.fr/ETM-Schurig/etm-powersync-energy-plugin-etm/src/branch/main/tools/etm-powersync-ref-optimizer/README.md). -## Pointing the engine at your optimiser {#brancher} +## Pointing the engine at your optimizer {#brancher} -Three JSON-RPC methods of the box, reserved to the administrator, described in -[`INTERFACE.md`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/INTERFACE.md): +Three JSON-RPC methods of the box (the first two reserved to the administrator); the box itself +returns their exact form through `JSONRPC.Introspect`: - `NymeaEnergy.SetOptimizerEndpoint` — where to connect (`unix:///…` or `tcp://host:port`); -- `NymeaEnergy.SetOptimizerToken` — the shared secret, the same as the optimiser's; -- `NymeaEnergy.GetOptimizerStatus` — connection status: optimiser alive, active strategy, +- `NymeaEnergy.SetOptimizerToken` — the shared secret, the same as the optimizer's; +- `NymeaEnergy.GetOptimizerStatus` — connection status: optimizer alive, active strategy, announced name, last error code. Over `tcp://` without encryption, the secret travels in clear text on the local network. ## The conformance suite {#conformite} -The `etm-powersync-optimizer-conformance` suite starts **your** optimiser and connects the +The `etm-powersync-optimizer-conformance` suite starts **your** optimizer and connects the **real** engine to it, on simulated devices. It checks, one function per point: 1. the handshake is accepted; 2. every `GetPlan` is answered within the engine's timeout; 3. the whole session, both ways, conforms to the contract embedded in the engine, validation rules included; -4. every plan is applied: the optimiser is in control; +4. every plan is applied: the optimizer is in control; 5. the safety loop stays on top: an out-of-bounds setpoint is clamped, a phase overload is shed. It does not judge the **quality** of the plans. -### Running it against your optimiser +### Running it against your optimizer Build the engine with its tests, then give the command that starts your server; `{endpoint}` in it is replaced by the address to listen on: ```sh -export ETM_POWERSYNC_OPTIMIZER_CMD='exec /path/to/my-optimiser --listen {endpoint}' +export ETM_POWERSYNC_OPTIMIZER_CMD='exec /path/to/my-optimizer --listen {endpoint}' export ETM_POWERSYNC_CONFORMANCE_EXPECT=plan # or abstain ``` Each function runs in its own process. The full command (network isolation recommended), the other variables (shared secret, start-up delay…) and how to read failures are in the -[suite's `README.md`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/tests/auto/conformance/README.md). +[suite's `README.md`](https://git.etm-powersync.fr/ETM-Schurig/etm-powersync-energy-plugin-etm/src/branch/main/tests/auto/conformance/README.md). ### Expected mode: `plan` or `abstain` {#mode-attendu} -`ETM_POWERSYNC_CONFORMANCE_EXPECT` tells the suite what your optimiser does: +`ETM_POWERSYNC_CONFORMANCE_EXPECT` tells the suite what your optimizer does: - **`plan`** (default): it is in control. Every cycle must apply its plan. - **`abstain`**: it abstains on every cycle — that is allowed, and conformant. The suite @@ -95,5 +95,5 @@ The mode is given, not guessed. The engine can record, on the box, a trace of every cycle (off by default, `NymeaEnergy.SetOptimizerTrace`). The `tools/etm-powersync-trace-replay` tool replays these -traces against a candidate optimiser and summarises the differences from the recorded plan. +traces against a candidate optimizer and summarises the differences from the recorded plan. Traces stay on site. diff --git a/docs/optimiseur/ecrire.md b/docs/optimiseur/ecrire.md index 90639d8..1b1e9d3 100644 --- a/docs/optimiseur/ecrire.md +++ b/docs/optimiseur/ecrire.md @@ -27,7 +27,7 @@ Trois points à ne pas manquer : 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). +[`tools/etm-powersync-ref-optimizer/`](https://git.etm-powersync.fr/ETM-Schurig/etm-powersync-energy-plugin-etm/src/branch/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. @@ -35,12 +35,12 @@ C'est un point de départ pour écrire le sien, et un point de comparaison : il 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). +[son `README.md`](https://git.etm-powersync.fr/ETM-Schurig/etm-powersync-energy-plugin-etm/src/branch/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) : +Trois méthodes JSON-RPC de la box (les deux premières réservées à l'administrateur) ; la box +en rend la forme exacte par `JSONRPC.Introspect` : - `NymeaEnergy.SetOptimizerEndpoint` — où se connecter (`unix:///…` ou `tcp://hôte:port`) ; - `NymeaEnergy.SetOptimizerToken` — le secret partagé, le même que celui de l'optimiseur ; @@ -77,7 +77,7 @@ 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). +[`README.md` de la suite](https://git.etm-powersync.fr/ETM-Schurig/etm-powersync-energy-plugin-etm/src/branch/main/tests/auto/conformance/README.md). ### Mode attendu : `plan` ou `abstain` {#mode-attendu} diff --git a/docs/optimiseur/index.en.md b/docs/optimiseur/index.en.md index 5986eec..80d0a72 100644 --- a/docs/optimiseur/index.en.md +++ b/docs/optimiseur/index.en.md @@ -2,57 +2,57 @@ IN PROGRESS -The protocol between the engine and an optimiser is published (version 1.1). Connecting -an optimiser is being tested on our test installation; the box does not need one to work. +The protocol between the engine and an optimizer is published (version 1.1). Connecting +an optimizer is being tested on our test installation; the box does not need one to work. -## What an optimiser is for +## What an optimizer is for The [engine's rules](../fonctionnalites/moteur.md) decide on the present: this minute's -surplus, shared according to your priorities. An optimiser looks further ahead. From the +surplus, shared according to your priorities. An optimizer looks further ahead. From the forecasts the engine hands it — PV production, base consumption, entered tariff — it proposes a **plan in time slots** over several hours: shift the water heater to the expected production peak, keep headroom for evening charging, and so on. -## The optimiser advises, the engine decides +## The optimizer advises, the engine decides - The engine only executes the **current slot** of the plan. The rest is shown as a forecast, and requested again on the next cycle. - Every setpoint is **capped** by the load's bounds (floor, ceiling, anti-flapping locks) and by the real-time **safety loop**, which stays with the engine and overrides - everything. An optimiser cannot bypass a lock. + everything. An optimizer cannot bypass a lock. - Every action must carry its **reason**. An action without one is rejected. - A malformed plan, or one that targets an unknown load, is rejected as a whole. -At worst, a faulty optimiser can therefore only propose a poor allocation — bounded by the +At worst, a faulty optimizer can therefore only propose a poor allocation — bounded by the engine. -## The box works without an optimiser +## The box works without an optimizer -Optimiser missing, silent, abstaining, plan expired or rejected: the engine returns to its +Optimizer missing, silent, abstaining, plan expired or rejected: the engine returns to its **rules** (`rules`) for that cycle, with no interruption of control. The app shows at all times which strategy is in charge. The Community edition works entirely this way. ## Its data come from the engine only -- The engine connects to the optimiser, never the other way round: the box opens no port. -- The optimiser runs on the box (local socket) or on a machine in your local network +- The engine connects to the optimizer, never the other way round: the box opens no port. +- The optimizer runs on the box (local socket) or on a machine in your local network (TCP). On the local network, a shared secret (token) is recommended. - It receives **only** the context the engine sends, forecasts included: it calls neither a weather service nor a tariff provider, and opens no connection to the outside. - What it learns stays on site. -## Who can write an optimiser +## Who can write an optimizer Anyone. The protocol is open and described by a [machine-readable contract](contrat.md) -published under GPL-3.0. A free **reference optimiser** and a **conformance suite** let you +published under GPL-3.0. A free **reference optimizer** and a **conformance suite** let you write your own and check it against the real engine — see [Writing an optimizer](ecrire.md). -## The ETM optimiser +## The ETM optimizer -ETM-Schurig offers its own proprietary optimiser, included in the Pro edition. It connects +ETM-Schurig offers its own proprietary optimizer, included in the Pro edition. It connects through this same protocol, within the same limits: it advises, the engine decides. At -handshake it announces itself as `etm-optimizer`; the reference optimiser announces itself +handshake it announces itself as `etm-optimizer`; the reference optimizer announces itself as `powersync-optimizer`. ## In this section @@ -60,4 +60,4 @@ as `powersync-optimizer`. - [Protocol](protocole.md) — transport, handshake, context, plan, fallback, validation rules. - [Contract](contrat.md) — the OpenRPC file that is authoritative on the shape of messages. -- [Writing an optimizer](ecrire.md) — reference optimiser and conformance suite. +- [Writing an optimizer](ecrire.md) — reference optimizer and conformance suite. diff --git a/docs/optimiseur/protocole.de.md b/docs/optimiseur/protocole.de.md index ce641b6..f0bebff 100644 --- a/docs/optimiseur/protocole.de.md +++ b/docs/optimiseur/protocole.de.md @@ -11,7 +11,7 @@ eigenen Kanal. Es ist nicht die API der App: Diese läuft über die Beschreibungen unverändert aus dem Vertrag, auf Französisch. Sie sind in allen drei Sprachen identisch. - **Die Bedeutung** ist ausführlich, auf Französisch, in - [`OPTIMIZER_PROTOCOL.md`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/docs/OPTIMIZER_PROTOCOL.md) + [`OPTIMIZER_PROTOCOL.md`](https://git.etm-powersync.fr/ETM-Schurig/etm-powersync-energy-plugin-etm/src/branch/main/docs/OPTIMIZER_PROTOCOL.md) im Repository der Engine beschrieben. Diese Seite fasst das Wesentliche zusammen; bei Abweichungen gelten die Dokumente der Engine. diff --git a/docs/optimiseur/protocole.en.md b/docs/optimiseur/protocole.en.md index 6b8ef51..5c98f33 100644 --- a/docs/optimiseur/protocole.en.md +++ b/docs/optimiseur/protocole.en.md @@ -1,6 +1,6 @@ # Protocol -The protocol links the box's energy **engine** to an **optimiser**, over a dedicated +The protocol links the box's energy **engine** to an **optimizer**, over a dedicated channel. It is not the app's API: the app goes through the [JSON-RPC API](../integrations/jsonrpc-api.md). @@ -10,13 +10,13 @@ channel. It is not the app's API: the app goes through the **generated** from it on every publication: framing in English, descriptions taken as-is from the contract, in French. They are identical in all three languages. - **The meaning** is described in detail, in French, in - [`OPTIMIZER_PROTOCOL.md`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/docs/OPTIMIZER_PROTOCOL.md), + [`OPTIMIZER_PROTOCOL.md`](https://git.etm-powersync.fr/ETM-Schurig/etm-powersync-energy-plugin-etm/src/branch/main/docs/OPTIMIZER_PROTOCOL.md), in the engine repository. This page gives the essentials; where they differ, the engine's documents prevail. ## Transport and roles {#transport} -- The optimiser is the **server**, the engine is the **client**: the engine connects and +- The optimizer is the **server**, the engine is the **client**: the engine connects and asks the questions. The box opens no port. - Two transports, same messages: `unix://` (local socket, default) and `tcp://` (machine on the local network). @@ -65,10 +65,10 @@ channel. It is not the app's API: the app goes through the ## Handshake {#handshake} On every connection, the engine sends `Handshake` with its protocol version and, if -configured, the shared secret. The optimiser answers with its version and, if it wishes, +configured, the shared secret. The optimizer answers with its version and, if it wishes, its name and capabilities. A different **major** version, a refused secret or an unreadable answer: the connection is refused, and the engine drives by its rules. If the -optimiser announces the action kinds (`kinds`) it emits, the engine then rejects any action +optimizer announces the action kinds (`kinds`) it emits, the engine then rejects any action of another kind. @@ -505,14 +505,14 @@ Undeclared fields: **rejected** (engine-emitted form, closed). ## The answer: a plan or an abstention {#reponse} -The optimiser answers **quickly** — with its last cached plan if it computes for long — +The optimizer answers **quickly** — with its last cached plan if it computes for long — and recomputes in the background. It answers either: - a **plan in time slots**: each slot carries one action per available load (setpoint in watts or amps, or SG-Ready state), each with its reason; only the current slot is executed, and `validUntil` bounds the plan's lifetime; - an **abstention** (`abstain: true`): "no plan right now". The engine drives by its rules - for that cycle, without treating the optimiser as failed. + for that cycle, without treating the optimizer as failed. An action's reason has two forms: a free text in French, **mandatory**, for the traces; and, optionally, a code from the catalogue (`reasonCode`) with its parameters. Only **the @@ -684,7 +684,7 @@ Type: map of number \| boolean \| string \| null ## `UpdateLearned` {#updatelearned} -Notification sent by the optimiser to the engine, with no answer, to pass on what it has +Notification sent by the optimizer to the engine, with no answer, to pass on what it has learned about the loads. In version 1.1 of the engine, it is received and logged, but not yet used. @@ -704,8 +704,8 @@ Envoyée par l'OPTIMISEUR (sens inverse des deux autres), sans id, sans réponse ## Fallback state machine {#repli} -There is no separate heartbeat: a valid answer to `GetPlan` means the optimiser is alive. -Failures are counted per request; after several consecutive failures, the optimiser is +There is no separate heartbeat: a valid answer to `GetPlan` means the optimizer is alive. +Failures are counted per request; after several consecutive failures, the optimizer is declared absent and the engine drives by its rules until the next valid plan. The app sees this state continuously (`optimizerAlive`, `activeStrategy`). @@ -763,7 +763,7 @@ Ce que le moteur refuse EN PLUS de la forme, dans l'ordre de ses contrôles (Opt ### Tolerances {#tolerances} -What the engine accepts beyond the contract. A conformant optimiser does not rely on it. +What the engine accepts beyond the contract. A conformant optimizer does not rely on it. diff --git a/docs/optimiseur/protocole.md b/docs/optimiseur/protocole.md index f40d7c4..db59ab3 100644 --- a/docs/optimiseur/protocole.md +++ b/docs/optimiseur/protocole.md @@ -9,7 +9,7 @@ dédié. Ce n'est pas l'API de l'application : celle-ci passe par l'[API JSON-RP **générés** à chaque publication : cadre en anglais, descriptions reprises telles quelles du contrat, en français. Ils sont identiques dans les trois langues. - **Le sens** est décrit en détail, en français, dans - [`OPTIMIZER_PROTOCOL.md`](https://github.com/etmschurig/etm-powersync-energy-plugin-etm/blob/main/docs/OPTIMIZER_PROTOCOL.md), + [`OPTIMIZER_PROTOCOL.md`](https://git.etm-powersync.fr/ETM-Schurig/etm-powersync-energy-plugin-etm/src/branch/main/docs/OPTIMIZER_PROTOCOL.md), dans le dépôt du moteur. Cette page en donne l'essentiel ; en cas d'écart, les documents du moteur l'emportent. diff --git a/docs/reference.en.md b/docs/reference.en.md index 03f06c1..cd10d6a 100644 --- a/docs/reference.en.md +++ b/docs/reference.en.md @@ -6,6 +6,6 @@ The box integrates with your tools through two local interfaces, on your network conventions — and its [full reference](api/index.md), generated from the box; - [MQTT](integrations/mqtt.md). -!!! note "What about the optimiser protocol?" - The channel between the engine and an optimiser is **not** an integration API: it +!!! note "What about the optimizer protocol?" + The channel between the engine and an optimizer is **not** an integration API: it has its own protocol, described in the [Optimizer](optimiseur/protocole.md) section. diff --git a/docs/tarifs.en.md b/docs/tarifs.en.md index dca4860..23d5f76 100644 --- a/docs/tarifs.en.md +++ b/docs/tarifs.en.md @@ -17,15 +17,15 @@ range. A tariff with several ranges is shown there read-only. !!! note "Exposed, not used to decide" The engine **exposes** the tariff (display, local recording); it does not decide - with it. Without an optimiser, control stays rule-based — see + with it. Without an optimizer, control stays rule-based — see [PV production forecast](fonctionnalites/prevision-pv.md#what-the-forecast-does-not-do). ## Dynamic tariffs ROADMAP Arbitration on national tariff signals — **France**: Tempo (blue/white/red), off-peak -and peak hours, dynamic offers; CO₂ optimisation from the RTE eco2mix signal. +and peak hours, dynamic offers; CO₂ optimization from the RTE eco2mix signal. **Germany**: variable tariffs, spot offers (EPEX), grid-responsive control of -controllable loads under **§14a EnWG**; CO₂ optimisation from **SMARD** +controllable loads under **§14a EnWG**; CO₂ optimization from **SMARD** (Bundesnetzagentur). !!! note "Roadmap"