136 lines
6.8 KiB
Markdown
136 lines
6.8 KiB
Markdown
|
|
# Brief agent — plugin V2C Trydan
|
|
|
|
> Repo : `etm-powersync-plugins-modbus` · Dossier : `v2c/` · Branche : `feature/v2c-trydan`
|
|
> Borne : V2C Trydan / Trydan Pro (monophasée·triphasée, ES). Comm locale : **Modbus TCP (port 502)** + **HTTP REST**.
|
|
> Statut cible : **Partiel** (comme Keba) — PAS dans la matrice beta validée. Ne pas promettre tant que non testé sur borne réelle.
|
|
|
|
---
|
|
|
|
## RÔLE
|
|
|
|
Créer le plugin nymea `v2c` dans `etm-powersync-plugins-modbus`, sur le modèle des plugins
|
|
existants du repo (abbterra pour la structure evcharger Modbus TCP, eastron pour le pattern
|
|
registres). ThingClass `trydan` implémentant l'interface **`evcharger`** — c'est elle que le
|
|
moteur energy-etm consomme (states `chargingEnabled`, `maxChargingCurrent`, `pluggedIn`,
|
|
`charging`, `currentPower` ; actions `setChargingEnabled`, `setMaxChargingCurrent`).
|
|
|
|
## TRANSPORT — décision d'architecture
|
|
|
|
**Modbus TCP = transport principal** (port 502, unit id 1). C'est le bus du repo, l'outillage
|
|
(`nymea-modbus-cli`, libnymea-modbus) existe, et le polling périodique colle au cycle du moteur.
|
|
|
|
**HTTP = complément, deux usages** :
|
|
1. **Découverte** : la Trydan est en WiFi/LAN, pas de discovery Modbus. `GET /RealTimeData`
|
|
(JSON) sert de probe d'identification pendant le setup (NetworkDeviceDiscovery + test HTTP).
|
|
2. **Fallback diagnostic** : si un champ manque en Modbus, le compléter par HTTP est permis,
|
|
mais le chemin de contrôle (pause, intensité) reste Modbus.
|
|
|
|
Ne PAS implémenter deux ThingClasses (une Modbus, une HTTP) — une seule, transport hybride interne.
|
|
|
|
## CARTE REGISTRES (source : lib officielle V2Charge/Trydan_Modbus_TCP)
|
|
|
|
Lecture : holding registers, **2 registres par valeur, décodage float 32 bits big-endian
|
|
(byte ET word order Big)**. Écriture : write_register simple (uint16).
|
|
|
|
### Lecture (0x0BC2…)
|
|
| Reg | Nom | Note |
|
|
|---|---|---|
|
|
| 0x0BC2 | ChargeState | 0=déconnecté, 1=connecté sans charge, 2=en charge (à confirmer sur borne) |
|
|
| 0x0BC3 | ChargePower | W |
|
|
| 0x0BC4 | ChargeEnergy | kWh session |
|
|
| 0x0BC5 | SlaveError | code erreur |
|
|
| 0x0BC6 | ChargeTime | s |
|
|
| 0x0BC7 | ValuePWM | duty CP |
|
|
| 0x0BC8 | HousePower | W — pince CT maison (si installée) |
|
|
| 0x0BC9 | PowerFV | W — production PV vue par la borne (si configurée) |
|
|
| 0x0BCA | PauseState | |
|
|
| 0x0BCB | Lock | |
|
|
| 0x0BCC | Program(Promgram) | |
|
|
| 0x0BCD | Intensity | A courante |
|
|
| 0x0BCE | Dynamic | mode dynamique V2C on/off |
|
|
| 0x0BCF | Payment | |
|
|
| 0x0BD0 | OCPP | |
|
|
| 0x0BD1 | MinIntensity | A |
|
|
| 0x0BD2 | MaxIntensity | A |
|
|
| 0x0BD3 | PauseDynamic | |
|
|
| 0x0BD4 | DynamicPowerMode | |
|
|
| 0x0BD5 | ContractedPower | W |
|
|
|
|
### Écriture (0x177A…)
|
|
| Reg | Nom | Usage HEMS |
|
|
|---|---|---|
|
|
| 0x177A | PauseState | **setChargingEnabled** (pause=1 → désactivé) |
|
|
| 0x177B | Lock | verrouillage |
|
|
| 0x177C | Program | timer interne — ne pas utiliser (conflit moteur) |
|
|
| 0x177D | Intensity | **setMaxChargingCurrent** (A) |
|
|
| 0x177E | Dynamic | voir CONFLIT ci-dessous |
|
|
| 0x177F | Payment | hors scope |
|
|
| 0x1780 | OCPP | hors scope |
|
|
| 0x1781 | MinIntensity | borne basse (6 A) |
|
|
| 0x1782 | MaxIntensity | borne haute (bug historique V2C corrigé upstream — vérifier firmware) |
|
|
| 0x1783 | PauseDynamic | voir CONFLIT |
|
|
| 0x1784 | DynamicPowerMode | voir CONFLIT |
|
|
| 0x1785 | ContractedPower | protection abonnement interne borne |
|
|
|
|
Vérifier la carte contre la feuille officielle V2C (lien dans le README du repo
|
|
V2Charge/Trydan_Modbus_TCP, gid=0) avant d'écrire les paramRegisters JSON.
|
|
|
|
## ⚠️ CONFLIT D'OPTIMISEURS — le piège central de cette borne
|
|
|
|
La Trydan embarque SON PROPRE pilotage solaire (« Dynamic », pince CT + lecture onduleur,
|
|
PID interne). Deux cerveaux ne doivent pas piloter la même borne :
|
|
|
|
- **Dynamic V2C ACTIF (0x0BCE=1)** → la borne s'autopilote au surplus ; toute écriture
|
|
Intensity du moteur sera combattue par le PID interne. Oscillations garanties.
|
|
- **Mode HEMS (le nôtre)** → exiger Dynamic=0 ; le moteur energy-etm décide, la borne obéit.
|
|
|
|
Comportement du plugin :
|
|
1. À l'init, LIRE 0x0BCE. Si Dynamic=1, exposer un state `conflictDetected` (ou équivalent)
|
|
et logger un avertissement explicite — ne PAS désactiver silencieusement le mode du client.
|
|
2. Setting de Thing `disableInternalOptimizer` (défaut: demander) : si l'utilisateur accepte,
|
|
écrire Dynamic=0 + PauseDynamic/DynamicPowerMode cohérents.
|
|
3. `decisionReason` côté moteur doit pouvoir refléter « borne en autopilotage V2C — pilotage
|
|
HEMS suspendu » si Dynamic revient à 1 (l'app V2C du client peut le réactiver à tout moment
|
|
→ re-lire à chaque poll, pas seulement à l'init).
|
|
|
|
C'est le même problème que la PV-Edition Keba : une borne « intelligente » à neutraliser
|
|
proprement pour que l'arbitrage central reste l'unique décideur.
|
|
|
|
## SÉCURITÉ / ROBUSTESSE
|
|
|
|
- Anti-flapping : respecter les verrous du moteur (chargingEnabledLockDuration etc.) — le
|
|
plugin n'introduit PAS sa propre cadence d'écriture ; il applique ce que le moteur envoie.
|
|
- Connexion Modbus perdue → states `connected=false`, pas de retry agressif (backoff).
|
|
- Écritures idempotentes : ne réécrire Intensity que si la valeur cible change réellement
|
|
(la borne journalise chaque write ; éviter l'usure flash et le spam).
|
|
- Min 6 A (IEC 61851). Clamper toute consigne < 6 A à pause plutôt qu'à une valeur illégale.
|
|
- Float decode : 2 registres, Big/Big. NE PAS supposer du uint16 sur les lectures.
|
|
|
|
## INTERDIT
|
|
|
|
- Toucher aux plugins publiés du repo (eastron, abbb2x, abbterra, waveshare-relay-d8).
|
|
- Promettre la borne dans la doc/matrice beta (statut Partiel, non testé matériel).
|
|
- Dépendance à un service privé ETM — plugin 100% GPL, parle à la borne en direct.
|
|
- Implémenter OCPP/Payment/RFID — hors scope HEMS.
|
|
|
|
## DEFINITION OF DONE
|
|
|
|
1. Plugin compile (amd64 + cross arm64) et s'intègre au .pro du repo.
|
|
2. ThingClass `trydan` expose l'interface `evcharger` complète + states diag
|
|
(HousePower, PowerFV, SlaveError, Dynamic/conflit).
|
|
3. Discovery réseau + setup par IP manuelle fonctionnels.
|
|
4. Gestion du conflit Dynamic implémentée (lecture à chaque poll, state, setting).
|
|
5. Testé contre simulateur Modbus (registres mockés) — le test sur borne réelle est
|
|
un jalon séparé, AVANT tout passage en « Supporté ».
|
|
6. Entrée PORTING_STATUS_modbus.md : statut Partiel, source de la carte registres notée.
|
|
|
|
## RÉFÉRENCES
|
|
|
|
- Lib officielle : github.com/V2Charge/Trydan_Modbus_TCP (carte registres + décodage float)
|
|
- API HTTP : feuille V2C (gid=1147522182) + github.com/V2Charge/API-doc-v2c — à vérifier,
|
|
endpoints probables /RealTimeData (lecture JSON) et /write/<param>=<val>
|
|
- Dans le repo : abbterra (structure evcharger Modbus TCP), PORTING_STATUS_modbus.md
|
|
- Firmware : les updates V2C mentionnent des fixes Modbus (Max/MinIntensity) — documenter
|
|
la version firmware minimale constatée lors du test réel.
|