# Divergences — vendor Fronius du plugin SunSpec Écarts assumés entre ce que demandent `specs/fronius-sunspec.md` et le contrat d'une part, et ce que le code fait d'autre part. Chaque entrée dit **pourquoi** et **comment la lever**. Deux étiquettes : - **MESURÉ** — l'écart repose sur une observation faite sur du matériel ou sur le code de la plateforme, reproductible. - **INFÉRÉ** — l'écart repose sur un raisonnement, faute de donnée. À reprendre dès qu'une mesure existe. --- ## D-1 — `meterSlaveId` n'est pas marqué `advanced` (MESURÉ) **Ce que demande AC-7.** Le paramètre `meterSlaveId` de la thingClass `froniusConnection` doit être `advanced`. **Ce que fait le code.** Rien : le paramètre n'a pas ce drapeau. **Pourquoi.** `advanced` n'est pas une propriété de paramType dans nymea 1.15.2. `ParamType::typeProperties()` énumère exactement `id`, `name`, `displayName`, `type`, `defaultValue`, `inputType`, `unit`, `minValue`, `maxValue`, `stepSize`, `allowedValues`, `readOnly`. Le vérificateur de métadonnée refuse tout champ inconnu : ``` Param type "meterSlaveId" has unknown fields: "advanced" ``` et `PluginMetadata::isValid()` passe à `false`. Ce n'est pas un paramètre mal affiché : **le plugin ne se charge plus du tout**, et les erreurs suivantes en cascade (le paramType est abandonné, donc `froniusConnection` ne satisfait plus l'interface `networkdevice`) rendent le diagnostic trompeur. Vérifié en chargeant le JSON, avec et sans le drapeau, dans un `PluginMetadata` lié à la `libnymea` installée — pas seulement lu dans une source amont qui pourrait diverger du paquet. **Comment lever.** Rien à faire côté plugin. Il faut soit que nymea ajoute la propriété, soit que AC-7 soit corrigé. Un test de garde (`test_F3_meter_slave_id_is_not_marked_advanced`) empêche qu'on ajoute le drapeau sans refaire la mesure. --- ## D-2 — délai de garde du balayage des enfants orphelins (INFÉRÉ) **Contexte.** `processDiscoveryResult()` fait disparaître les things enfants dont le modèle n'est plus annoncé. Avec deux connexions sous le même parent, chacune ne voit que la moitié du tableau : balayer sur cette moitié ferait disparaître les enfants de l'autre à chaque découverte. Le balayage attend donc que **toutes** les connexions du parent aient réussi une découverte, puis confronte les enfants à l'union de leurs modèles. **L'écart.** Une connexion dont la découverte n'aboutit jamais bloquerait le balayage pour toujours. Un délai de garde le débloque : `OrphanSweepGraceSeconds = 600` (10 minutes). **Pourquoi cette valeur, et pourquoi elle est INFÉRÉE.** Aucune donnée ne la fixe. Le choix est asymétrique et volontairement paresseux : un balayage trop tardif laisse traîner un thing périmé affiché déconnecté, un balayage trop précoce **supprime un thing de l'utilisateur**. À conséquences inégales, réglage prudent. 10 minutes est très au-delà de tout cycle de découverte observé, sans être infini. **Comment lever.** Mesurer, sur le banc puis sur matériel, le temps que met une découverte SunSpec à échouer définitivement sur un unit ID qui ne répond pas (timeout × retries × nombre de registres de base balayés). Le délai de garde doit valoir quelques fois cette durée, pas dix minutes arbitraires. La valeur est un seul `const` dans `integrationpluginsunspec.cpp` ; la changer n'a d'effet sur rien d'autre. --- ## D-3 — la configuration du plugin écrase les défauts de cadence Fronius (MESURÉ, préexistant) **Contexte.** `createConnection()` impose `timeout` et `numberOfRetries` du vendor Fronius (AC-8) à la création. Mais `onPluginConfigurationChanged()` réapplique ensuite les valeurs globales du plugin à **toutes** les connexions, Fronius comprise. **L'écart.** Il est antérieur à F3 et affecte déjà la connexion onduleur seule. F3 ne le corrige pas ; il l'étend symétriquement à la connexion compteur, pour que les deux connexions d'un même thing se comportent identiquement. Le plancher d'intervalle d'interrogation d'AC-8, lui, reste appliqué : il vit dans `effectiveUpdateInterval()`, pas ici. **Comment lever.** Hors périmètre de F3 : cela demande de décider si les réglages globaux du plugin doivent pouvoir passer outre un défaut vendor, ce que ni le contrat ni la spec ne tranchent. --- ## D-4 — connexion détruite par `ThingSetupInfo::aborted` et laissée dans la table (MESURÉ, préexistant, amont) **Contexte.** `setupThing()` relie `ThingSetupInfo::aborted` à `SunSpecConnection::deleteLater()`, alors que `createConnection()` a déjà inséré la connexion dans `m_sunSpecConnections`. Un setup avorté laisse donc un pointeur pendant dans la table ; le setup suivant du même thing prend la branche « reconfiguration » et appelle `deleteLater()` sur un objet déjà détruit. **L'écart.** F3 ne corrige pas ce chemin pour la connexion primaire : il est commun aux trois vendors, y compris `solarEdge` dont aucun test ne couvre le comportement, et le périmètre du lot est explicitement « generic et solarEdgeConnection ne changent pas de comportement ». La connexion **compteur** ajoutée par F3, elle, se retire proprement de sa table à la destruction. **Comment lever.** Relier `QObject::destroyed` au retrait de la table pour les deux connexions, dans un lot qui assume de toucher le chemin commun, avec une couverture de test pour `solarEdge`.