[3c-6] degradedMode() + notification ChargingSchedulesChanged + invariant zéro-cloud
virtual degradedMode() dans SmartChargingManager (base false, [ETM] additif), override EnergyArbitrator. Champ o:degradedMode (additif) dans la notification NymeaEnergy.ChargingSchedulesChanged, émise aussi aux transitions du mode dégradé (planif suspendue → push du flag via emit chargingSchedulesChanged()). INTERFACE.md : champ degradedMode documenté. SAFETY.md : notification réconciliée (ChargingSchedulesChanged, pas EnergyManagerChanged) + limite "valeur figée non détectée". Correction ZÉRO CLOUD : suppression de la section "Alertes externes" / mécanisme n8n, remplacée par une signalisation 100% locale (notification nymea in-app + buzzer/relais via règle nymea, aucun canal réseau sortant). Invariant 10 "ZÉRO cloud" gravé dans AGENTS.md. Build 0 erreur / 0 warning. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
312a2484ae
commit
f71e0405b4
@ -181,6 +181,12 @@ Règles absolues :
|
||||
après pilotage.
|
||||
9. **Aucun composant propriétaire ici** (Héos = repo privé `etm-powersync-optimizer`).
|
||||
Ce repo doit compiler et tourner seul, GPL pur.
|
||||
10. **ZÉRO cloud** — aucun appel réseau sortant vers un service distant (ni n8n, ni mail,
|
||||
ni push tiers). Le système fonctionne sans internet (autoconsommation, local-first).
|
||||
Toute alerte est **locale** : notification nymea in-app + signalisation physique
|
||||
(buzzer/relais via règle nymea). Le moteur expose l'état, il ne contacte personne.
|
||||
Exception : le plugin est CLIENT d'un optimiseur sur socket local/LAN (OPTIMIZER_PROTOCOL,
|
||||
`unix://` ou `tcp://` du réseau de l'installation) — jamais un service cloud externe.
|
||||
|
||||
## RÉPONSES FIGÉES (ne plus poser ces questions)
|
||||
|
||||
|
||||
12
INTERFACE.md
12
INTERFACE.md
@ -453,10 +453,18 @@ S'abonner via `JSONRPC.SetNotificationStatus` avec le namespace `"NymeaEnergy"`.
|
||||
---
|
||||
|
||||
### `NymeaEnergy.ChargingSchedulesChanged`
|
||||
Émis à chaque recalcul du planning (cycle ~1 min).
|
||||
Émis à chaque recalcul du planning (cycle ~1 min), **et** à chaque transition du mode
|
||||
dégradé L2 (watchdog fraîcheur compteur).
|
||||
```json
|
||||
{ "chargingSchedules": [ ... ] }
|
||||
{
|
||||
"chargingSchedules": [ ... ],
|
||||
"o:degradedMode": false
|
||||
}
|
||||
```
|
||||
- `degradedMode` *(bool, optionnel — [ETM])* : `true` quand le compteur est muet depuis
|
||||
> 90 s et que les consignes de repli L2 sont actives (planification suspendue, ECS coupé,
|
||||
EV en charge clampé au minimum). Repasse à `false` au retour du compteur. Champ additif :
|
||||
les clients antérieurs l'ignorent. Détail : `docs/SAFETY.md` §L2.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -88,13 +88,35 @@ indépendante de la défaillance du contrôleur est le rôle de L3 (watchdog sys
|
||||
|
||||
### Notification client (dans ce repo)
|
||||
|
||||
- Une notification nymea `EnergyManagerChanged` est émise avec un flag `degradedMode: true`.
|
||||
- La notification JSON-RPC `NymeaEnergy.ChargingSchedulesChanged` porte un champ additif
|
||||
`degradedMode` (bool). Elle est émise aux **transitions** du mode dégradé (entrée/sortie),
|
||||
en plus des recalculs de planning. Voir `INTERFACE.md`.
|
||||
- L'application affiche : *"Supervision compteur perdue — charge EV maintenue au minimum"*.
|
||||
|
||||
### Alertes externes (hors de ce repo)
|
||||
### Limite — détection par fraîcheur uniquement
|
||||
|
||||
Les notifications push/mail/SMS sont déclenchées via l'infra ETM (n8n) sur réception
|
||||
de l'événement nymea. Aucun code de notification externe dans ce plugin.
|
||||
Le watchdog L2 détecte l'**absence de mise à jour** du compteur (plus de signal
|
||||
`powerBalanceChanged` depuis > 90 s), pas une **valeur figée**. Un compteur qui continue
|
||||
d'émettre une valeur strictement constante (capteur bloqué mais lien vivant) n'est **pas**
|
||||
détecté par cette couche — `m_lastMeterUpdate` reste frais. Détecter une valeur figée
|
||||
(variance nulle sur fenêtre) est hors scope L2 ; le cas est couvert au niveau matériel/L0
|
||||
et par la supervision externe.
|
||||
|
||||
### Signalisation locale (zéro cloud)
|
||||
|
||||
ETM PowerSync est **100 % autonome, zéro cloud** : aucune alerte ne sort vers un service
|
||||
distant (ni n8n, ni mail, ni push tiers). Le système est conçu pour fonctionner **sans
|
||||
internet** (argument produit : autoconsommation, local-first). Le `degradedMode` est
|
||||
signalé par deux canaux strictement locaux :
|
||||
|
||||
- **Notification nymea in-app** (déjà implémentée : champ `degradedMode`) — canal principal
|
||||
vers le client connecté à l'application.
|
||||
- **Signal sonore local optionnel** (buzzer GPIO ou canal relais) piloté par une **Règle
|
||||
nymea** déclenchée sur `degradedMode` — pour le client sur place, sans application.
|
||||
Aucun code buzzer dans ce repo : le moteur **expose** l'état, la signalisation est une
|
||||
Thing nymea + une règle (configuration d'installation, cf. `## Signalisation locale`).
|
||||
|
||||
**Aucun canal sortant réseau.** Voir l'invariant « ZÉRO cloud » dans `AGENTS.md`.
|
||||
|
||||
### Sortie du mode dégradé
|
||||
|
||||
@ -169,6 +191,10 @@ déclenchée sur ces événements — configuration installation, documentée da
|
||||
Aucun code buzzer/relais dans ce repo. Principe : le moteur émet, la configuration
|
||||
d'installation décide quoi signaler.
|
||||
|
||||
**Zéro cloud** : toute la signalisation est locale (notification nymea in-app +
|
||||
signalisation physique). Aucun appel réseau sortant vers un service distant — le système
|
||||
fonctionne sans internet. Invariant gravé dans `AGENTS.md`.
|
||||
|
||||
---
|
||||
|
||||
## Correspondance couches / scénarios de défaillance
|
||||
|
||||
@ -38,6 +38,7 @@ EnergyArbitrator::EnergyArbitrator(EnergyManager *em, ThingManager *tm,
|
||||
if (m_degradedMode) {
|
||||
qCInfo(dcNymeaEnergy()) << "[Arbitre] Compteur de nouveau actif — sortie du mode dégradé L2.";
|
||||
m_degradedMode = false;
|
||||
emit chargingSchedulesChanged(); // pousse degradedMode=false (planif reprend au cycle suivant)
|
||||
}
|
||||
});
|
||||
// QTimer (et non signal) : doit rester actif quand le compteur est muet.
|
||||
@ -223,6 +224,7 @@ void EnergyArbitrator::onMeterWatchdogTick()
|
||||
void EnergyArbitrator::applyDegradedMode(const QDateTime &now)
|
||||
{
|
||||
m_degradedMode = true;
|
||||
emit chargingSchedulesChanged(); // pousse degradedMode=true (notification client L2)
|
||||
const QString reason =
|
||||
QStringLiteral("Compteur muet depuis >90 s — consigne de repli (L2 watchdog)");
|
||||
|
||||
|
||||
@ -84,6 +84,14 @@ public:
|
||||
*/
|
||||
void registerEcsAdapter(EcsRelayAdapter *adapter);
|
||||
|
||||
/*!
|
||||
* \brief Mode dégradé L2 actif (compteur muet > 90 s) — override de SmartChargingManager.
|
||||
* \return \c true tant que les consignes de repli L2 tiennent ; \c false en régime normal.
|
||||
* \note Exposé dans la notification \c NymeaEnergy.ChargingSchedulesChanged (champ
|
||||
* \c degradedMode), émise aussi aux transitions de ce flag.
|
||||
*/
|
||||
bool degradedMode() const override { return m_degradedMode; }
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* \brief Boucle principale ETM — surcharge SmartChargingManager::update().
|
||||
|
||||
@ -197,6 +197,9 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
params.clear();
|
||||
description = "Emitted whenever the planed charging schedules have changed.";
|
||||
params.insert("chargingSchedules", QVariantList() << objectRef<ChargingSchedule>());
|
||||
// [ETM] degradedMode : true quand le watchdog L2 a basculé en repli (compteur muet).
|
||||
// Optionnel (additif, rétro-compatible) ; émis aussi aux transitions du mode dégradé.
|
||||
params.insert("o:degradedMode", enumValueName(Bool));
|
||||
registerNotification("ChargingSchedulesChanged", description, params);
|
||||
|
||||
// Charing manager
|
||||
@ -223,6 +226,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
schedules << pack<ChargingSchedule>(schedule);
|
||||
}
|
||||
params.insert("chargingSchedules", schedules);
|
||||
params.insert("degradedMode", m_smartChargingManager->degradedMode()); // [ETM] L2
|
||||
emit ChargingSchedulesChanged(params);
|
||||
});
|
||||
|
||||
|
||||
@ -72,6 +72,10 @@ public:
|
||||
|
||||
ChargingSchedules chargingSchedules() const;
|
||||
|
||||
// [ETM] Mode dégradé L2 (watchdog fraîcheur compteur). Base = false ;
|
||||
// overridé dans EnergyArbitrator. Exposé pour la notification JSON-RPC.
|
||||
virtual bool degradedMode() const { return false; }
|
||||
|
||||
SpotMarketManager *spotMarketManager() const;
|
||||
|
||||
#ifdef ENERGY_SIMULATION
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user