docs(v2c): PORTING_STATUS à jour - cause racine martèlement résolue (connexion persistante), lecture+écriture validées, reste régulation VE
This commit is contained in:
parent
186f195900
commit
f814720962
@ -1,59 +1,88 @@
|
||||
## v2c / trydan — V2C Trydan (e-charger)
|
||||
|
||||
**Statut : Partiel** — validé partiellement sur borne réelle, PAS encore « Supporté ».
|
||||
Ne pas promettre dans la matrice beta tant que le test « VE branché » n'est pas bouclé.
|
||||
**Statut : Partiel (proche de Supporté)** — transport, décodage, lecture ET écriture validés
|
||||
sur borne réelle. Connexion persistante validée par tcpdump (fin du martèlement).
|
||||
RESTE : un seul jalon = régulation de puissance réelle avec VE branché (prévu ce soir).
|
||||
Ne pas passer « Supporté » dans la matrice beta tant que ce dernier test n'est pas bouclé.
|
||||
|
||||
| Champ | Valeur |
|
||||
|---|---|
|
||||
| Plugin | `powersync-plugin-v2c` (création ETM, pas un fork) |
|
||||
| Paquet | `powersync-plugin-v2c` 1.15.0+etm1, dépend de `libnymea-modbus` (via ${shlibs:Depends}) |
|
||||
| Interface | `evcharger` |
|
||||
| Transport validé | **Modbus TCP** (port 502, unit id 1) |
|
||||
| Fallback / discovery | HTTP REST (`/RealTimeData`, `/write/<param>=<val>`) |
|
||||
| Borne de test | V2C Trydan, IP 192.168.1.127 |
|
||||
| Borne de test | V2C Trydan, ID `XE47OR`, IP 192.168.1.127 |
|
||||
| Firmware testé | **2.4.6** |
|
||||
| Date | 2026-06-12 |
|
||||
| Date MAJ | 2026-06-13 |
|
||||
|
||||
### Sources de la carte registres
|
||||
- Lib officielle V2C : `github.com/V2Charge/Trydan_Modbus_TCP` (`src/v2ctrydan/modbus.py`).
|
||||
- Feuille officielle « V2C - Datamanager Modbus TCP & RTU » (gid=0).
|
||||
- Lib officielle V2C : `github.com/V2Charge/Trydan_Modbus_TCP`.
|
||||
- Feuille officielle « V2C - Datamanager Modbus TCP & RTU ».
|
||||
- Référence comportementale : evcc `charger/trydan.go` (HTTP) — logique enable/PauseDynamic.
|
||||
|
||||
### Validé sur borne réelle (192.168.1.127, fw 2.4.6)
|
||||
- **Transport Modbus TCP** : répond proprement (0 timeout) une fois le lien WiFi désaturé.
|
||||
- **Décodage float Big/Big** confirmé : MaxIntensity (0x0BD2/3026) lu = 20.0.
|
||||
Vérif registre brut : 3026 = 16800 = 0x41A0 → float32 0x41A00000 = 20.0. Little-endian = garbage.
|
||||
- **Transport Modbus TCP** : 0 timeout en poll espacé. Confirmé :
|
||||
- poll 1 valeur / 30 s, 5 min → 0 échec ;
|
||||
- poll bloc 20 reg / 30 s, 5 min → 0 échec ;
|
||||
- cycle read(6 valeurs)+write / 15 s, 10 min → 0 timeout lecture, 18/18 écritures OK, SlaveError=0.
|
||||
- **Décodage float Big/Big** confirmé : MaxIntensity (0x0BD2/3026) lu = 20.0 (brut 0x41A0).
|
||||
- **Lecture validée** : ChargeState (0=A,1=B,2=C), ChargePower, MaxIntensity, puissances par phase.
|
||||
- **Écriture validée** (FC6 uint16) : Intensity écrite=14 → relue=14 ; écrite=8 → relue=8 (vérif HTTP).
|
||||
- **Activation de charge** validée via écriture Modbus (PauseState/Lock).
|
||||
- **ChargePower non-nul pendant charge** : observé (reg 0x0BC3 remonte une puissance réelle).
|
||||
- **Gestion conflit Dynamic** confirmée (cœur du plugin) :
|
||||
- Dynamic=1 → toute consigne Intensity est écrasée par le PID interne (consigne 10 → relue 0).
|
||||
- Écriture PauseDynamic=1 → la consigne Intensity=10 **tient** (relue 10, Dynamic=0, PauseDynamic=1).
|
||||
- Écriture PauseDynamic=0 → optimiseur interne rendu au client.
|
||||
- `Dynamic` observé basculant seul 0→1→0 pendant la session → **relecture à chaque poll obligatoire** (confirmé empiriquement, pas seulement à l'init).
|
||||
- **ChargeState** 0/1/2 = A/B/C : cohérent (0 = déconnecté observé borne au repos).
|
||||
- **SlaveError** : valait 4 le matin (VE branché), repassé à 0 borne au repos → code 4 probablement
|
||||
lié à l'état de charge, pas un défaut permanent. À confirmer.
|
||||
- Dynamic=1 → consigne Intensity écrasée par le PID interne.
|
||||
- PauseDynamic=1 → la consigne Intensity tient.
|
||||
- `Dynamic` peut basculer seul 0→1 → **relecture à chaque poll obligatoire**.
|
||||
- Corroboré par evcc issue #28157.
|
||||
- **SlaveError** (reg 0x0BC5) décodé, table officielle : 00=OK, 01=Communication, 02=Reading,
|
||||
03=Slave, **04=Waiting WiFi**, 05=Waiting communication, 06=Wrong IP, 07=Slave not found,
|
||||
08=Wrong Slave, 09=No response, 10=Clamp not connected. Le code 4 vu en saturation = perte WiFi.
|
||||
- **Puissances par phase** : L1 (0x0BD9/3033), L2 (0x0BDA/3034), L3 (0x0BDB/3035) — exposées
|
||||
en states diag, permettent de détecter le basculement mono/tri autonome de la borne.
|
||||
|
||||
### RESTE À VALIDER (jalon « VE branché »)
|
||||
- **setMaxChargingCurrent régule la charge réelle** (pas seulement le registre). Sans VE, la borne
|
||||
garde Intensity=0 même consigne acceptée → test impossible borne au repos.
|
||||
- Comportement de `chargingEnabled` (PauseState/Lock en miroir) sous charge active.
|
||||
- `ChargePower` / `currentPower` non-nul à confirmer pendant une charge.
|
||||
- `sessionEnergy` (ChargeEnergy 0x0BC4) : NE PAS exposer tant que monotonie/reset non vérifiés
|
||||
(cf. evcc issue #28047, ChargeRater retiré pour fiabilité firmware).
|
||||
### RESTE À VALIDER (dernier jalon « VE branché », prévu ce soir)
|
||||
- **setChargingCurrent régule la charge réelle** : ChargePower doit suivre la consigne
|
||||
(paliers 6→10→16 A). Script de test prêt (retry espacés 15 s, grep "Written").
|
||||
- Confirmer le basculement mono/tri visible via Power_L1/L2/L3 sous charge.
|
||||
|
||||
### LIMITATIONS MATÉRIELLES IMPORTANTES (à documenter pour l'installation client)
|
||||
1. **WiFi sature si le cloud V2C / l'app reste actif.** Latence observée : 14 000 ms et 100% perte
|
||||
avec app/cloud actifs → 0 timeout possible. Après fermeture app + déconnexion cloud : 20-143 ms,
|
||||
0% perte, exploitable. **Conséquence prod : le plugin doit être le seul maître à parler à la
|
||||
borne ; déconnecter la borne du cloud V2C en installation HEMS, ou timeouts généreux (≥2-3 s)
|
||||
et poll espacé.** Lien radio lui-même bon (5 ms au mieux) — c'est la saturation ESP32, pas le signal.
|
||||
### CAUSE RACINE RÉSOLUE — saturation borne = bug plugin (pas la borne)
|
||||
Diagnostic confirmé par tcpdump le 2026-06-13 : la première version du plugin **ouvrait/fermait
|
||||
la socket Modbus TCP à chaque cycle de poll**, avec rafale de 6-7 SYN à chaque ouverture +
|
||||
FIN/RST après lecture → saturait l'interface WiFi de l'ESP32 (latence 30 ms → 10-18 s, jusqu'à
|
||||
100% timeout, état cumulatif).
|
||||
- Preuve : mbpoll avec **connexion persistante** + poll espacé = 0% échec, là où le plugin
|
||||
open/close = timeouts en boucle.
|
||||
- **FIX (commit 186f195)** : connexion TCP persistante, établie une fois et maintenue ;
|
||||
connectDevice() retourne si déjà ConnectedState ; pas de reconnexion sur simple timeout de
|
||||
lecture ; reconnexion seulement si la socket tombe réellement, avec backoff.
|
||||
- **Validation tcpdump post-fix** : 1 seul SYN au démarrage, puis uniquement échanges Modbus
|
||||
(length 12/13), ZÉRO SYN/FIN/RST entre les polls. Borne stable, réagit aux commandes nymea-app.
|
||||
|
||||
### LIMITATIONS MATÉRIELLES (à documenter pour l'installation client)
|
||||
1. **WiFi de l'ESP32 sensible au polling rapide.** Sous sollicitation rapprochée (ping continu
|
||||
1/s, ou retry serrés, ou clients concurrents), l'interface WiFi sature de façon cumulative
|
||||
(latence jusqu'à 18 s) et réversible (repos/reboot restaure). Lien radio lui-même bon (min ~10 ms).
|
||||
**Conséquences install :**
|
||||
- Poll espacé (30 s) + timeouts généreux (≥2-3 s), pas de retry agressif → 0% échec validé.
|
||||
- **nymead doit être l'UNIQUE maître** de la borne. Déconnecter le cloud V2C et fermer l'app
|
||||
V2C en installation HEMS (sinon clients concurrents = re-saturation).
|
||||
- Le moteur energy-etm passe par nymead, jamais en direct sur la borne (jamais 2 maîtres).
|
||||
- Problème reproduit indépendamment : Home Assistant (issue #124295), evcc.
|
||||
2. **RS485 non exploitable comme transport HEMS sur ce modèle.** Le port RS485 (RJ45, pin 4=B-,
|
||||
pin 5=A+) est réservé par V2C au rôle « Modbus Feeder / lecture compteur PV » pour la fonction
|
||||
Dynamic (mode maître). Aucune réponse esclave obtenue sur le bus partagé (testé IDs 1/2/3 @ 9600
|
||||
et 19200, 100% timeout). Le mode « commande à distance » esclave passe par TCP, pas par le RS485
|
||||
physique. **→ Étape 2 (RTU) du plugin non applicable à cette borne.** Le RS485 reste pertinent
|
||||
pour d'autres bornes du catalogue, pas pour la Trydan.
|
||||
pin 5=A+) est réservé par V2C au rôle « Modbus Feeder / lecture compteur PV » (mode maître).
|
||||
Aucune réponse esclave obtenue sur bus partagé (IDs 1/2/3 @ 9600 et 19200, 100% timeout).
|
||||
Le mode « commande à distance » passe par TCP. **→ Étape 2 (RTU) du plugin non applicable
|
||||
à cette borne.** Le RS485 reste pertinent pour d'autres bornes du catalogue.
|
||||
|
||||
### Notes plugin
|
||||
- Clamp courant : doit lire **MaxIntensity de la borne** (= 20 ici), PAS une constante 32 en dur
|
||||
(le `qBound(6, val, 32)` actuel est à corriger — la borne plafonne à 20). [À FIXER]
|
||||
- Lectures : transactions individuelles de 2 registres, float Big/Big, pas de block read.
|
||||
- **Clamp courant** : lire **MaxIntensity de la borne** (= 20 ici), PAS une constante 32 en dur.
|
||||
[À VÉRIFIER que le fix est appliqué dans la version courante]
|
||||
- Lectures : transactions individuelles de 2 registres, float Big/Big, **pas de block read**
|
||||
(chevauchement registres confirmé : un bloc retourne des paires mal alignées).
|
||||
- Logique enable : `chargingEnabled = (PauseState==0 ET Lock==0)`, écritures en miroir.
|
||||
- **NE PAS écrire** MaxIntensity (reg 0x1782/6018) = plafond physique installation.
|
||||
- Connexion : **persistante** (ne jamais open/close par poll — cf. cause racine ci-dessus).
|
||||
- `sessionEnergy` (ChargeEnergy 0x0BC4) : NE PAS exposer tant que monotonie/reset non vérifiés
|
||||
(cf. evcc issue #28047, ChargeRater retiré pour fiabilité firmware).
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user