From 2931d295bc1e11d4dbb3e9dc5251f1531d3f06a2 Mon Sep 17 00:00:00 2001 From: Patrick Schurig Date: Sat, 6 Jun 2026 08:00:07 +0200 Subject: [PATCH] docs: add INTERFACE.md with complete NymeaEnergy JSON-RPC API Co-Authored-By: Claude Sonnet 4.6 --- INTERFACE.md | 513 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 513 insertions(+) create mode 100644 INTERFACE.md diff --git a/INTERFACE.md b/INTERFACE.md new file mode 100644 index 0000000..80cad2c --- /dev/null +++ b/INTERFACE.md @@ -0,0 +1,513 @@ +# INTERFACE.md — API JSON-RPC du plugin `nymea-energy-plugin-nymea` + +> Ce fichier fait autorité sur l'interface exposée par le plugin. +> Mettre à jour ce fichier à chaque modification de l'API. +> +> **Namespace :** `NymeaEnergy` +> **Versions enregistrées :** 0–8 (`registerExperienceHandler(..., 0, 8)`) +> **Transport :** WebSocket JSON-RPC 2.0, port 4444 (nymea standard) + +--- + +## Enums + +### `ChargingMode` +| Valeur | Description | +|---|---| +| `ChargingModeNormal` | Recharge immédiate au maximum disponible | +| `ChargingModeEco` | Recharge sur surplus solaire uniquement | +| `ChargingModeEcoWithTargetTime` | Eco + deadline de fin (`endDateTime` + `targetPercentage`) | +| `ChargingModeEcoWithMinCurrent` | Eco + courant minimum garanti (6 A) si pas de surplus | +| `ChargingModeEcoMinWithTargetTime` | Eco + courant minimum + deadline | + +### `ChargingState` (lecture seule — calculé par le manager) +| Valeur | Description | +|---|---| +| `ChargingStateIdle` | Pas de recharge active | +| `ChargingStateSurplusCharging` | Recharge sur surplus solaire en cours | +| `ChargingStateSpotMarketCharging` | Recharge sur créneau spot market en cours | +| `ChargingStateTimeRequirement` | Recharge forcée pour atteindre la deadline | + +### `ChargingActionIssuer` +| Valeur | Description | +|---|---| +| `ChargingActionIssuerUnknown` | Émetteur non identifié | +| `ChargingActionIssuerSurplusCharging` | Action émise par le surplus manager | +| `ChargingActionIssuerSpotMarketCharging` | Action émise par le spot market manager | +| `ChargingActionIssuerTimeRequirement` | Action émise pour honorer la deadline | +| `ChargingActionIssuerOverloadProtection` | Action émise par la protection surcharge | + +### `EnergyError` +| Valeur | Description | +|---|---| +| `EnergyErrorNoError` | Succès | +| `EnergyErrorMissingParameter` | Paramètre obligatoire absent | +| `EnergyErrorInvalidParameter` | Valeur de paramètre invalide | + +--- + +## Types + +### `ChargingInfo` +Configuration d'une borne EV. Seuls les champs marqués `(writable)` peuvent être modifiés via `SetChargingInfo` — les autres sont ignorés ou read-only. + +| Champ | Type | Writable | Description | +|---|---|---|---| +| `evChargerId` | `Uuid` | — | Identifiant de la borne (obligatoire dans SetChargingInfo) | +| `assignedCarId` | `Uuid` | ✓ | Véhicule associé (optionnel) | +| `chargingMode` | `ChargingMode` | ✓ | Mode de recharge | +| `endDateTime` | `DateTime` | ✓ | Deadline cible (EcoWithTargetTime / EcoMinWithTargetTime) | +| `repeatDays` | `[Int]` | ✓ | Jours de répétition (0=Lun … 6=Dim, liste vide = pas de répétition) | +| `targetPercentage` | `Uint` | ✓ | Niveau batterie cible en % (défaut : 80) | +| `chargingState` | `ChargingState` | — | État calculé (lecture seule) | +| `spotMarketChargingEnabled` | `Bool` | ✓ | Activer la recharge sur spot market | +| `dailySpotMarketPercentage` | `Uint` | ✓ | % de la charge quotidienne à faire en heures spot bon marché | + +### `ChargingAction` +Action envoyée au charger physique (présente dans les schedules). + +| Champ | Type | Description | +|---|---|---| +| `chargingEnabled` | `Bool` | Activer/désactiver la recharge | +| `maxChargingCurrent` | `Double` | Courant max en Ampères | +| `desiredPhaseCount` | `Uint` | Nombre de phases souhaitées (1 ou 3) | +| `issuer` | `ChargingActionIssuer` | Origine de la décision | + +### `ChargingSchedule` +Créneau de recharge planifié (résultat du calcul du manager). + +| Champ | Type | Description | +|---|---|---| +| `evChargerId` | `Uuid` | Borne concernée | +| `startDateTime` | `DateTime` | Début du créneau | +| `endDateTime` | `DateTime` | Fin du créneau | +| `action` | `ChargingAction` | Action prévue sur ce créneau | + +### `ScoreEntry` +Entrée de cotation horaire du spot market, avec pondération relative. + +| Champ | Type | Description | +|---|---|---| +| `startDateTime` | `DateTime` | Début du créneau tarifaire | +| `endDateTime` | `DateTime` | Fin du créneau tarifaire | +| `value` | `Float` | Prix brut (€/MWh, selon provider) | +| `weighting` | `Float` | Pondération relative : 0.0 = le plus cher, 1.0 = le moins cher | + +### `SpotMarketProviderInfo` +Fournisseur de données spot market disponible. + +| Champ | Type | Description | +|---|---|---| +| `providerId` | `Uuid` | Identifiant du provider | +| `name` | `String` | Nom affiché | +| `country` | `Uint` | Pays (`QLocale::Country`) | +| `website` | `String` | URL du site du provider | + +**Providers enregistrés :** +| Nom | `providerId` | +|---|---| +| aWATTar AT | `5196b3cc-b2ee-46d6-b63a-7af2cf70ba67` | +| aWATTar DE | `0ca6ad88-e243-438d-a0f8-986cecf61834` | + +--- + +## Méthodes + +> Notation : `o:` = paramètre optionnel. Tous les appels requièrent un token d'auth nymea. + +--- + +### Overload protection + +#### `NymeaEnergy.GetPhasePowerLimit` +Retourne la limite de courant par phase configurée. + +**Params :** aucun + +**Returns :** +```json +{ "phasePowerLimit": 25 } +``` +> `0` signifie non configuré — tout le smart charging est désactivé. + +--- + +#### `NymeaEnergy.SetPhasePowerLimit` +Définit la limite de courant par phase (en Ampères). `0` désactive le smart charging. + +**Params :** +```json +{ "phasePowerLimit": 25 } +``` + +**Returns :** +```json +{ "energyError": "EnergyErrorNoError" } +``` + +--- + +### Paramètres de recharge + +#### `NymeaEnergy.GetAcquisitionTolerance` +Retourne le seuil de surplus nécessaire pour démarrer une recharge Eco. + +**Params :** aucun + +**Returns :** +```json +{ "acquisitionTolerance": 0.5 } +``` +> Valeur entre 0.0 et 1.0. Plus la valeur est haute, plus il faut de surplus. + +--- + +#### `NymeaEnergy.SetAcquisitionTolerance` +**Params :** +```json +{ "acquisitionTolerance": 0.5 } +``` + +**Returns :** +```json +{ "energyError": "EnergyErrorNoError" } +``` +> Retourne `EnergyErrorInvalidParameter` si hors de `[0.0, 1.0]`. + +--- + +#### `NymeaEnergy.GetBatteryLevelConsideration` +Retourne le facteur de prise en compte du stockage batterie dans le calcul du surplus. + +**Params :** aucun + +**Returns :** +```json +{ "batteryLevelConsideration": 0.9 } +``` +> 0.0 = stockage ignoré, 1.0 = surplus réduit intégralement de la puissance de charge batterie. + +--- + +#### `NymeaEnergy.SetBatteryLevelConsideration` +**Params :** +```json +{ "batteryLevelConsideration": 0.9 } +``` + +**Returns :** +```json +{ "energyError": "EnergyErrorNoError" } +``` +> Retourne `EnergyErrorInvalidParameter` si hors de `[0.0, 1.0]`. + +--- + +#### `NymeaEnergy.GetLockOnUnplug` +Retourne si la borne doit être verrouillée à la déconnexion du véhicule. + +**Params :** aucun + +**Returns :** +```json +{ "lockOnUnplug": false } +``` + +--- + +#### `NymeaEnergy.SetLockOnUnplug` +**Params :** +```json +{ "lockOnUnplug": true } +``` + +**Returns :** +```json +{ "energyError": "EnergyErrorNoError" } +``` + +--- + +### Configuration EV + +#### `NymeaEnergy.GetChargingInfos` +Retourne la configuration de recharge de toutes les bornes, ou d'une seule. + +**Params :** +```json +{ "o:evChargerId": "uuid-de-la-borne" } +``` + +**Returns :** +```json +{ + "chargingInfos": [ + { + "evChargerId": "uuid-de-la-borne", + "assignedCarId": "uuid-du-car", + "chargingMode": "ChargingModeEco", + "chargingState": "ChargingStateSurplusCharging", + "endDateTime": "2025-06-15T08:00:00+02:00", + "repeatDays": [1, 2, 3, 4, 5], + "targetPercentage": 80, + "spotMarketChargingEnabled": false, + "dailySpotMarketPercentage": 0 + } + ] +} +``` + +--- + +#### `NymeaEnergy.SetChargingInfo` +Met à jour la configuration d'une borne. Seuls les champs `USER true` sont modifiables (voir type `ChargingInfo`). Les autres champs sont ignorés. + +**Params :** +```json +{ + "chargingInfo": { + "evChargerId": "uuid-de-la-borne", + "chargingMode": "ChargingModeEcoWithTargetTime", + "endDateTime": "2025-06-15T08:00:00+02:00", + "targetPercentage": 80 + } +} +``` + +**Returns :** +```json +{ "energyError": "EnergyErrorNoError" } +``` + +--- + +#### `NymeaEnergy.GetChargingSchedules` +Retourne le planning de recharge calculé (toutes les bornes, horizon ~24h). + +**Params :** aucun + +**Returns :** +```json +{ + "chargingSchedules": [ + { + "evChargerId": "uuid-de-la-borne", + "startDateTime": "2025-06-15T02:00:00+02:00", + "endDateTime": "2025-06-15T04:30:00+02:00", + "action": { + "chargingEnabled": true, + "maxChargingCurrent": 16.0, + "desiredPhaseCount": 1, + "issuer": "ChargingActionIssuerSpotMarketCharging" + } + } + ] +} +``` + +--- + +### Spot market + +#### `NymeaEnergy.GetAvailableSpotMarketProviders` +Retourne la liste des providers spot market disponibles. + +**Params :** aucun + +**Returns :** +```json +{ + "providers": [ + { + "providerId": "5196b3cc-b2ee-46d6-b63a-7af2cf70ba67", + "name": "aWATTar AT", + "country": 14, + "website": "https://www.awattar.at" + }, + { + "providerId": "0ca6ad88-e243-438d-a0f8-986cecf61834", + "name": "aWATTar DE", + "country": 82, + "website": "https://www.awattar.de" + } + ] +} +``` + +--- + +#### `NymeaEnergy.GetSpotMarketConfiguration` +Retourne la configuration spot market courante. + +**Params :** aucun + +**Returns :** +```json +{ + "enabled": true, + "available": true, + "o:providerId": "5196b3cc-b2ee-46d6-b63a-7af2cf70ba67" +} +``` +> `providerId` est absent si `enabled` est `false`. + +--- + +#### `NymeaEnergy.SetSpotMarketConfiguration` +Active ou désactive le spot market et sélectionne le provider. + +**Params :** +```json +{ + "enabled": true, + "o:providerId": "5196b3cc-b2ee-46d6-b63a-7af2cf70ba67" +} +``` +> Si `enabled: true`, `providerId` est obligatoire et doit être un UUID valide. + +**Returns :** +```json +{ "energyError": "EnergyErrorNoError" } +``` +> Retourne `EnergyErrorInvalidParameter` si `enabled: true` sans `providerId`, ou `providerId` inconnu. + +--- + +#### `NymeaEnergy.GetSpotMarketScoreEntries` +Retourne les cotations pondérées du provider actif. Liste vide si désactivé ou non disponible. + +**Params :** aucun + +**Returns :** +```json +{ + "spotMarketScoreEntries": [ + { + "startDateTime": "2025-06-15T00:00:00+02:00", + "endDateTime": "2025-06-15T01:00:00+02:00", + "value": 45.2, + "weighting": 0.85 + } + ] +} +``` + +--- + +## Notifications + +S'abonner via `JSONRPC.SetNotificationStatus` avec le namespace `"NymeaEnergy"`. + +--- + +### `NymeaEnergy.PhasePowerLimitChanged` +```json +{ "phasePowerLimit": 25 } +``` + +--- + +### `NymeaEnergy.AcquisitionToleranceChanged` +```json +{ "acquisitionTolerance": 0.5 } +``` + +--- + +### `NymeaEnergy.BatteryLevelConsiderationChanged` +```json +{ "batteryLevelConsideration": 0.9 } +``` + +--- + +### `NymeaEnergy.LockOnUnplugChanged` +```json +{ "lockOnUnplug": true } +``` + +--- + +### `NymeaEnergy.ChargingInfoAdded` +Émis quand une nouvelle borne est détectée et sa `ChargingInfo` créée. +```json +{ "chargingInfo": { ... } } +``` + +--- + +### `NymeaEnergy.ChargingInfoRemoved` +Émis quand une borne est supprimée. +```json +{ "evChargerThingId": "uuid-de-la-borne" } +``` + +--- + +### `NymeaEnergy.ChargingInfoChanged` +Émis à chaque modification de la `ChargingInfo` (config ou état). +```json +{ "chargingInfo": { ... } } +``` + +--- + +### `NymeaEnergy.ChargingSchedulesChanged` +Émis à chaque recalcul du planning (cycle ~1 min). +```json +{ "chargingSchedules": [ ... ] } +``` + +--- + +### `NymeaEnergy.SpotMarketConfigurationChanged` +Émis quand le provider actif, l'état enabled ou l'état available change. +```json +{ + "enabled": true, + "available": true, + "o:providerId": "5196b3cc-b2ee-46d6-b63a-7af2cf70ba67" +} +``` + +--- + +### `NymeaEnergy.SpotMarketStatusChanged` +Émis quand `enabled` ou `available` change (sans les détails du provider). +```json +{ "enabled": true, "available": true } +``` + +--- + +### `NymeaEnergy.SpotMarketScoreEntriesChanged` +Émis quand les cotations sont mises à jour par le provider. +```json +{ "spotMarketScoreEntries": [ ... ] } +``` + +--- + +## Interfaces nymea consommées + +Le plugin détecte les appareils **par interface**, jamais par ThingClassId. + +| Interface | États lus | Actions envoyées | +|---|---|---| +| `evcharger` | `chargingEnabled`, `maxChargingCurrent`, `pluggedIn`, `charging`, `currentPhaseA/B/C`, `currentPowerPhaseA/B/C` | `setChargingEnabled`, `setMaxChargingCurrent` | +| `electricvehicle` | `batteryLevel`, `maxChargingCurrent`, `capacity` | — | +| `rootmeter` / `energymeter` | `currentPowerPhaseA/B/C`, `currentPhaseA/B/C` | — | +| `energystorage` | `currentPower`, `batteryLevel` | — | + +**Déclencheur du cycle :** signal `PowerBalanceEntryAdded` de `nymea-experience-plugin-energy` (~1 min). + +--- + +## Notes d'intégration + +- Les timestamps sont des `QDateTime` sérialisés ISO 8601 avec timezone. +- Les puissances sont en **Watts**, les courants en **Ampères**. +- `phasePowerLimit` est en **Ampères** (par phase), pas en Watts. +- `weighting` des `ScoreEntry` : 1.0 = créneau le moins cher, 0.0 = le plus cher. +- `SetChargingInfo` est partiel : seuls les champs présents sont appliqués, sauf `evChargerId` qui est toujours requis. +- Le plugin fonctionne sans `powersync-optimizer` (mode Community, dégradé proprement).