etm-powersync-app/test/flux_sens_reseau_test.dart
Patrick Schurig a6dd319ef2 fix(rôles): le compteur RÉSEAU n'est plus détecté comme compteur solaire
Signalé sur banc après changement de matériel : Fronius SunSpec retiré, Eastron
SDM72 posé en rootMeter et SDM120 en compteur de production. L'écran affichait le
SDM72 dans les DEUX rôles, avec « auto · lecture seule » — donc sans moyen de le
corriger.

La box était juste (`GetRootMeter` rend bien le SDM72) et les interfaces
distinguaient les deux sans ambiguïté :

  Grid / sdm72          : energymeter, smartmeter, connectable
  PV   / sdm120Producer : smartmeterproducer, smartmeter, connectable

C'est notre liste qui ne discriminait pas : le rôle solaire acceptait
`energymeter`, `meter` et `smartmeter` — portées par TOUT compteur, réseau
compris — et ignorait `smartmeterproducer`, la seule qui dise « ce compteur
mesure une production ».

Deux corrections, la seconde tenant même si une future classe déclare des
interfaces trop larges :

- le rôle solaire exige désormais une interface de production ;
- le Thing acté comme compteur RACINE n'est plus candidat à aucun autre rôle.

Reste ouvert, et c'est le vrai fond du signalement : une détection automatique
ne devrait pas être un cul-de-sac. Les lignes de compteur n'ont aujourd'hui
AUCUN geste — pas de sélecteur, quel que soit l'état. Le badge « lecture seule »
est honnête, mais une inférence fausse doit pouvoir se corriger.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
2026-09-06 12:31:59 +02:00

61 lines
2.7 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/// **Le sens du flux réseau** — signalé sur appareil, pas trouvé en test.
///
/// Le 2026-09-06 : 4,9 kW de production, 3,3 kW de consommation, le simulateur affichant
/// `Grid -1980 W` — donc une installation qui **injecte** — et l'app annonçait « consommation
/// réseau », flèche à l'envers.
///
/// La cause n'était pas un calcul mais une **convention écrite deux fois, en sens opposés** :
///
/// | endroit | ce qu'il disait | juste ? |
/// |---|---|---|
/// | `EnergyData.gridPower` (commentaire) | « + injection, − soutirage » | **non** |
/// | `energy_flow_widget.dart:180` | « gridPower > 0 = soutirage » | oui |
/// | `energy_flow_card.dart` (le code à l'écran) | + = injection | **non** |
///
/// Vérifié à la sonde : `currentPowerAcquisition` vaut **−2 511 W** pendant que la production
/// (5,76 kW) dépasse la consommation (3,25 kW) de 2,5 kW. Le signe négatif est donc l'export,
/// et sa valeur absolue la puissance injectée.
///
/// Ces tests portent sur les accesseurs nommés plutôt que sur le widget : c'est là que la
/// convention vit désormais, et c'est ce qui empêche qu'un troisième lecteur la réinvente.
library;
import 'package:etm_powersync_app/models/energy_data.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('la convention est celle de la BOX : + soutiré, − injecté', () {
test('export : le relevé du 2026-09-06', () {
// production 5 763 W, maison 3 252 W -> 2 511 W injectés.
const d = EnergyData(pvPower: -5763, homePower: 3252, gridPower: -2511);
expect(d.gridExportW, 2511);
expect(d.gridImportW, 0, reason: 'rien n\'est soutiré pendant qu\'on injecte');
});
test('import : le cas du soir, production nulle', () {
const d = EnergyData(pvPower: 0, homePower: 3250, gridPower: 3250);
expect(d.gridImportW, 3250);
expect(d.gridExportW, 0);
});
test('zéro : ni l\'un ni l\'autre — et surtout pas les deux', () {
const d = EnergyData(gridPower: 0);
expect(d.gridImportW, 0);
expect(d.gridExportW, 0);
});
test('les deux parts ne sont JAMAIS non nulles ensemble', () {
// C'est la garde qui aurait attrapé l'inversion : le code fautif calculait
// `import = -gridPower` et `export = gridPower`, donc l'un des deux était toujours
// faux — mais chacun pris seul restait plausible.
for (final w in [-9000.0, -1.0, 0.0, 1.0, 9000.0]) {
final d = EnergyData(gridPower: w);
expect(d.gridImportW * d.gridExportW, 0,
reason: 'à $w W, une seule direction peut être active');
expect(d.gridImportW + d.gridExportW, w.abs(),
reason: 'et leur somme est la puissance échangée');
}
});
});
}