# AGENTS.md — etm-powersync-plugins-modbus Tous les plugins Modbus supportés par ETM : plugins propres et forks de plugins amont. Compteurs, bornes de recharge, relais, onduleurs. - **Licence** : GPL-3.0 pour les plugins, LGPL-3.0 pour `libnymea-modbus` / `libnymea-sunspec` - **Miroir public** : OUI - **Paquets** : publiés sur `repos.etm-powersync.fr`, trois canaux L'inventaire des plugins est l'arborescence du dépôt. Ne pas se fier à une liste écrite ici : elle serait périmée, et un agent en conclurait que le reste n'existe pas. Ce dépôt est autoportant : tout ce qui est nécessaire pour y travailler est ici. ## Placement du travail non amont Une fois qu'un développement — plugin, correctif, extension vendor — n'est ni upstream officiel ni destiné à y retourner à court terme, il vit dans le dépôt produit ETM correspondant (`etm-powersync-plugins-modbus` ou `etm-powersync-plugins`), vendoré depuis sa source si elle existe ailleurs (`VENDORED.md` avec commit et date), développé directement sinon. Le fork correspondant (`nymea-plugins-modbus` ou `nymea-plugins`) ne garde que ce qui reste candidat à une contribution amont. ## Branches et canaux ``` feature/* ──► landing-silo ──► experimental-silo ──► main (nightly) (testing) (stable) ``` Vers la droite on promeut, vers la gauche on redescend un correctif. Une correction ne saute jamais un cran. Les trois branches existent sur le remote depuis le 2026-08-02. Les deux silos ont été créés vides depuis `main` ; `landing-silo` a ensuite reçu `feature/fronius-sunspec` comme premier contenu, `experimental-silo` est encore au niveau de `main`. Avant cette date le modèle ci-dessus était une intention, pas un état du dépôt. `experimental-silo` n'est pas une branche de travail : elle ne reçoit que ce qui a déjà survécu au nightly. Le travail se fait dans `feature/*`. ### Critères de promotion | Passage | Critère | |---|---| | commits dans `feature/*` | `verify` en local, l'agent boucle seul | | `feature/*` → `landing-silo` | PR, `verify` vert sur le runner, AC de la spec couverts par des tests | | `landing-silo` → `experimental-silo` | build complet propre, banc nocturne vert | | `experimental-silo` → `main` | validation matérielle nommée : appareil, firmware, configuration | Le dernier critère n'est pas automatisable et ne doit pas l'être. ### Correctifs **Avant de créer une branche : reproduire le bug et déterminer la branche la plus proche de `main` où il apparaît.** C'est elle qui décide du point de départ, pas l'urgence ressentie. | Le bug se reproduit… | Départ | Ensuite | |---|---|---| | jusque dans `main` | `hotfix/*` depuis `main` | fusion dans `main`, puis redescente dans `experimental-silo`, puis dans `landing-silo` | | dans `experimental-silo`, pas dans `main` | `fix/*` depuis `experimental-silo` | redescente dans `landing-silo` | | seulement dans `landing-silo` | `fix/*` depuis `landing-silo` | rien, il remonte par la promotion normale | Ne jamais corriger en aval un bug présent en amont : le correctif remontera un jour, mais la branche amont reste cassée entre-temps et la promotion suivante réintroduit l'ancien code par dessus. Symptôme : « le correctif ne tient pas ». Si une fusion casse le nightly, **révoquer la fusion** dans `landing-silo` pour rendre le canal de nouveau utilisable, puis corriger tranquillement dans la branche `feature/*` d'origine. Ne pas corriger en avant sous pression. Trois préfixes, pas davantage : `feature/*`, `fix/*`, `hotfix/*`. ### Versionnement des paquets Tout paquet issu d'un dépôt produit ETM porte un suffixe `+etmN` sur la version amont qu'il modifie ou remplace (ex. `1.15.2+etm1`), à tous les canaux de promotion (`landing-silo`/nightly, `experimental-silo`/testing, `main`/stable). Ce suffixe garantit la préséance apt/dpkg sur le paquet upstream identique. Ne jamais le remplacer par un tiret (`-etmN`) : `-` a un sens réservé en version Debian (champ `debian_revision`) et entre en conflit avec une éventuelle révision Debian amont. ## Agents Les agents travaillent dans `feature/*` et `fix/*`. Jamais de commit direct dans `landing-silo`, `experimental-silo` ou `main` : ces branches ne reçoivent que des fusions. Une spec, une branche, un jeu de critères d'acceptation. Un agent qui estime qu'un refactor s'impose sur un plugin publié le signale et s'arrête. Il ne le fait pas. ## Invariants locaux 1. **NE PAS renommer les paquets PUBLIÉS** : `powersync-plugin-eastron`, `powersync-plugin-abbb2x`, `nymea-plugin-abbterra`. Casse l'upgrade des box beta. Valable sur toutes les branches : un renommage dans `landing-silo` finit par atteindre `main`. 2. `abbterra` est volontairement sous nom amont (transition upstream propre) — ne pas « corriger ». 3. Matrice validée beta : SDM72 / SDM120 (eastron), Waveshare D8. 4. Aucun composant propriétaire ici. Aucun ne doit y entrer. ## Miroir public — ne doit jamais être commité Données client : adresses de site, noms, numéros de série, relevés, adresses IP d'installations réelles. Identifiants et jetons. Documentation constructeur sous réserve de confidentialité — elle se cite en référence (titre, version, section) dans la table de provenance des registres, jamais en contenu. Les captures, journaux et dumps de registres joints à un correctif sont expurgés avant commit. --- ## Repository Guidelines These conventions apply to every `*-plugins-modbus` repository. They are not a style preference: plugins from all of them load into the **same nymea-core**, so they share its ABI, its Qt version, its plugin metadata format and its interface definitions. A repository that diverges produces plugins that do not interoperate. **Target: nymea-core ``.** Where these guidelines and the core repository's `AGENTS.md` disagree, the core repository wins and this section is corrected. This section is identical, byte for byte, across every `*-plugins-modbus` repository, and is the part that can be contributed upstream. Anything specific to one repository belongs above it. ### Plugin anatomy One directory per vendor, holding its sources, headers, plugin metadata (`*.json`), translations and packaging fragments. Plugin IDs, translation filenames and resource prefixes follow the directory name. Shared code stays in the shared libraries. Never move code between an LGPL library and a GPL plugin without addressing the licence change explicitly. ### Build Requires `plugin.pri`, provided by `libnymea1-dev`, or passed explicitly via `PLUGIN_PRI=`. ``` qmake .pro && make -j"$(nproc)" # whole repository cd && qmake .pro && make # single plugin — the short loop, preferred ``` Select the Qt version before calling qmake. When building against a nymea source tree rather than a system-wide install, `PKG_CONFIG_PATH`, `CPATH`, `LIBRARY_PATH`, `LD_LIBRARY_PATH` and a `PATH` extended with the `nymea-plugininfocompiler` build directory are also required. Verbose logs: `QT_LOGGING_RULES="*.debug=true"`. ### Style Qt conventions: 4-space indent, `CamelCase` classes, `lowerCamelCase` functions and members with the `m_` prefix, Qt containers and signals over STL, log output wrapped in `NYMEA_LOGGING_CATEGORY`, and `foreach` rather than range-based `for` to keep C++11 compatibility. Refresh translations whenever user-visible text changes. ### Register provenance **Never infer a register address.** Every address comes from the manufacturer's documentation or from a read performed against a real device. A value taken from a third-party implementation is a hypothesis until verified on hardware, and is documented as such. Addresses, scale factors and endianness belong in the vendor's register description, not scattered as literals through the implementation. ### Hardware validation Compiling is not verifying. Any claim of validation names the device, its firmware version and its configuration. Without hardware, say so and describe the validation still required rather than implying it was performed. Where a Modbus server can be simulated, prefer a captured register dump replayed against the plugin over a hand-written mock: a dump carries the quirks a mock will not. ### Device writes A write can damage equipment or void a warranty. Write paths are reviewed more strictly than read paths: state what is written, under which conditions, and what happens if the plugin stops mid-operation. ### Commits and pull requests Imperative subjects under ~72 characters. Pull request titles: `Plugin name: Add support for xyz` or `New plugin: Plugin name`. State whether the change was tested on hardware, and if not, name someone who can confirm it. Update the plugin's `README.md` and the translations. Call out packaging impacts — Qt 5 and Qt 6 packaging are maintained separately.