sunspecStorage déclarait `battery` mais pas `energystorage`. Les trois consommateurs qui filtrent par cette interface ne la trouvaient donc pas : le bilan de puissance de nymea (`currentPowerStorage`, celui que le CLIENT lit sur son tableau de bord), la réserve de stockage de la recharge VE, et celle du waterfall. Vérifié sans authentification dans `energylogs.sqlite` de .75 : la colonne `storage` de `powerBalance` est à 0.0 sur toutes les lignes, pendant que la batterie affiche 50 % et « Holding ». Elle n'était pas à zéro, elle était invisible. Ce n'était pas une ligne de JSON. `energystorage` exige `currentPower` (W, signé) et `capacity` (kWh), qu'aucun des quatorze états ne portait, et les déclarer sans les câbler aurait donné une batterie éternellement inerte — pire que son absence, puisque la réserve lirait « ni charge ni décharge » au lieu de « je ne sais pas ». D'où viennent les deux états. Le modèle 124 ne porte AUCUNE puissance : WChaMax est un maximum, StorAval est en ampères-heures. La puissance instantanée vit dans le modèle 160, réparti sur deux blocs `StCha` et `StDisCha` dont le `DCW` est un uint16 toujours positif, l'inactif à zéro. D'où `currentPower = DCW[StCha] - DCW[StDisCha]`, positif en charge, conformément à libnymea/interfaces/energystorage.json (« positive is 'consumed' »). C'est l'INVERSE de la convention constructeur du contrat §4, et `FroniusRules::batteryPower()` est réécrite comme la négation stricte de la nouvelle `storageCurrentPower()` pour qu'aucune des deux ne dérive seule. `capacity` vient de WHRtg du modèle 120, et l'état est laissé tranquille plutôt que mis à zéro quand le nameplate ne l'implémente pas. Le signe est MESURÉ, pas déduit. Banc .211 unité 1, consigne batterie imposée par MQTT, registres relus en lecture seule : +2000 W -> StCha 2000,0 W StDisCha 0,0 W ChaSt Charging -1500 W -> StCha 0,0 W StDisCha 1500,0 W ChaSt Discharging Le même relevé a montré `DCW_SF` passant de -2 à -1 entre repos et charge : le facteur d'échelle n'est jamais mis en cache d'un relevé à l'autre. Écart assumé, D-9 dans DIVERGENCES.md : `sunspecStorage` est partagé avec le vendor générique, et les interfaces se déclarent par thingClass. Un appareil générique publiant le 124 sans le 160 porte désormais `energystorage` avec un `currentPower` figé à zéro. Les trois alternatives sont pires — une thingClass Fronius distincte détruirait le Thing existant et son historique. Le plugin avertit donc UNE FOIS par thing quand il ne trouve pas de source de puissance, en distinguant « pas de modèle 160 » de « modèle 160 sans bloc batterie ». Ça ne remplace pas la mesure, mais ça retire le silence. La cohérence des unités avec l'interface est vérifiée à la COMPILATION par nymea-plugininfocompiler : mettre `KiloWattHour` sur `currentPower` fait échouer le build. Onze tests `test_D9_*` figent le reste. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y3gzsuwENJfJtvuNDT3xGn
184 lines
10 KiB
Plaintext
184 lines
10 KiB
Plaintext
etm-powersync-plugins-modbus (1.15.2+etm10) trixie; urgency=medium
|
|
|
|
* sunspec: make the SunSpec storage visible to the energy engine. The
|
|
sunspecStorage thing class declared "battery" but not "energystorage", so
|
|
the three consumers that filter by that interface never found it: nymea's
|
|
power balance (currentPowerStorage, the figure the customer reads on their
|
|
dashboard), the storage reserve of the EV surplus charging, and the reserve
|
|
of the whole waterfall. Observed on the bench: GetPowerBalance answering
|
|
currentPowerStorage 0 while the battery reported 50 % and "Holding". It was
|
|
not at zero, it was invisible.
|
|
* sunspec: publish currentPower and capacity on the storage, wired to
|
|
registers rather than declared empty. Model 124 carries no power at all -
|
|
WChaMax is a maximum, StorAval is in amp hours - so the instantaneous power
|
|
is read from model 160, whose StCha and StDisCha blocks each carry an
|
|
unsigned DCW with the inactive one at zero. currentPower is therefore
|
|
DCW[StCha] - DCW[StDisCha], positive when charging, per the convention of
|
|
libnymea/interfaces/energystorage.json. capacity comes from WHRtg of the
|
|
nameplate model 120, and is left alone rather than zeroed when the
|
|
nameplate does not implement it.
|
|
* sunspec: the sign is measured, not deduced. Read only on the bench with the
|
|
battery power driven over MQTT: a +2000 W charge order gives StCha 2000 W,
|
|
StDisCha 0 W and ChaSt Charging; a -1500 W discharge order gives StCha 0 W,
|
|
StDisCha 1500 W and ChaSt Discharging. The same run showed DCW_SF moving
|
|
from -2 to -1 between idle and load, which is why the scale factor is never
|
|
cached across a poll.
|
|
* sunspec: warn once per thing when a storage has no power source - no model
|
|
160 on its connection, or a model 160 with no StCha/StDisCha block. Such a
|
|
thing now claims energystorage while reporting a flat zero, and a silent
|
|
zero is what made the original defect expensive. See DIVERGENCES.md D-9.
|
|
|
|
-- Patrick Schurig <patrick@etm-schurig.eu> Wed, 26 Aug 2026 14:00:00 +0200
|
|
|
|
etm-powersync-plugins-modbus (1.15.2+etm9) trixie; urgency=medium
|
|
|
|
* sunspec: read Fronius float32 points big endian, the way the hardware
|
|
emits them. byteOrder() returned ByteOrderLittleEndian on the grounds that
|
|
"the SunSpec default is assumed"; that conflated the default of the
|
|
specification with libnymea-sunspec's own, which is the opposite. Every
|
|
float32 of the Fronius personality was therefore read with its two
|
|
registers swapped. Measured on a Symo, read only: the model 213 meter on
|
|
unit 200 serves Hz = 4248 0000, which is 50.0000 big endian and 2.3777e-41
|
|
swapped. Reproduced on the bench: a meter importing 2.7 kW reported as
|
|
exporting 107 MW, with the arbiter switching every load on, and the thing
|
|
still reporting itself connected with no Modbus error. The meter sign fix
|
|
only becomes observable once this is right. solarEdge already forces big
|
|
endian and the generic vendor keeps its user parameter; neither changes.
|
|
* sunspec: add tools/read-float-order.py, a read-only probe that decodes Hz
|
|
and PhVphA both ways so the word order can be settled by measurement
|
|
rather than assumption.
|
|
|
|
-- Patrick Schurig <patrick@etm-schurig.eu> Fri, 07 Aug 2026 07:00:00 +0200
|
|
|
|
etm-powersync-plugins-modbus (1.15.2+etm8) trixie; urgency=medium
|
|
|
|
* sunspec: ask the connection thing directly instead of resolving it by id.
|
|
The battery presence gate went through isFroniusChild(), which looks the
|
|
parent up in myThings(). During the initial setup the parent is not
|
|
registered yet, the lookup answers false, the Fronius gate is bypassed and
|
|
the phantom storage child is created after all. Caught on the bench, not
|
|
by the unit suite, which covers the decision and not the wiring. See
|
|
sunspec/DIVERGENCES.md D-7.
|
|
|
|
-- Patrick Schurig <patrick@etm-schurig.eu> Wed, 05 Aug 2026 19:20:00 +0200
|
|
|
|
etm-powersync-plugins-modbus (1.15.2+etm7) trixie; urgency=medium
|
|
|
|
* sunspec: correct the grid meter sign on Fronius. onMeterBlockUpdated()
|
|
negated the power of every meter model regardless of vendor, but the
|
|
Fronius Smart Meter already reports in the nymea convention, where a
|
|
negative value is feed-in. The negation is now undone for meters sitting
|
|
under a froniusConnection and only for those; generic and solarEdge keep
|
|
their previous behaviour. Established on a Primo GEN24 3.0, whose single
|
|
phase inverter gives the direction reference: the plugin reported the
|
|
inverter's own phase as importing while the two phases carrying no source
|
|
read as exporting. The arbiter concluded "insufficient surplus" and left
|
|
the water heater and the heat pump off while the site was exporting.
|
|
The energy counters were already correct and are left alone.
|
|
* sunspec: stop creating a phantom battery on Fronius. A hybrid GEN24
|
|
publishes model 124 whether or not a battery is wired to it, so a storage
|
|
child was created unconditionally and sat on batteryCritical forever. The
|
|
child is now created only when a physical quantity says a battery is
|
|
there. The state of charge is deliberately not used: 0% cannot be told
|
|
apart from a real but empty battery. See sunspec/DIVERGENCES.md D-6, the
|
|
battery-present side is still inferred.
|
|
|
|
-- Patrick Schurig <patrick@etm-schurig.eu> Wed, 05 Aug 2026 15:58:00 +0200
|
|
|
|
etm-powersync-plugins-modbus (1.15.2+etm6) trixie; urgency=medium
|
|
|
|
* sunspec: package the vendored SunSpec plugin as nymea-plugin-sunspec-etm01.
|
|
The plugin was added to the build by the vendoring commit but never
|
|
packaged, so dh_missing found its .so in debian/tmp with nowhere to install
|
|
it and aborted the whole source package: no binary package at all came out
|
|
of this branch, not even for the four unrelated plugins.
|
|
* sunspec: add the Fronius vendor. A GEN24 answers for the inverter on one
|
|
unit ID and for its Smart Meter on another, behind the same host and port,
|
|
so one froniusConnection thing now carries two SunSpecConnection objects.
|
|
The meter connection is brought up only once the primary has finished
|
|
discovering, and the parent connected state follows the primary alone.
|
|
* sunspec: correct the storage setpoint chain - charge and discharge rates
|
|
read back from InWRte/OutWRte instead of the read-only gradients, the rate
|
|
range widened to -100..100 so forced charging can be expressed at all,
|
|
enableDischarging reconciled from StorCtl_Mod, and the revert timer armed
|
|
with every setpoint so one left behind by a stopped HEMS expires.
|
|
* debian: add libnymea-sunspec-dev to Build-Depends. Upstream does not need
|
|
it because it builds libnymea-sunspec from the same source tree; this
|
|
repository vendors only the plugin and links against the installed library.
|
|
* The new binary package conflicts with, replaces and provides
|
|
nymea-plugin-sunspec: it ships the same plugin file and the same pluginId
|
|
as the upstream package this repository already mirrors.
|
|
|
|
-- ETM-Schurig SARL <contact@etm-schurig.eu> Sun, 02 Aug 2026 12:05:00 +0200
|
|
|
|
etm-powersync-plugins-modbus (1.15.2+etm5) trixie; urgency=medium
|
|
|
|
* abbterra: decode the serial-number and firmware register fields as BCD, as
|
|
specified by the ABB Modbus spec §5.1 (e.g. 0x49 = week 49, 0x22 = 22 kW),
|
|
instead of as plain binary. The binary reading made deviceInfoFromValues()
|
|
reject every real charger whose BCD production-week byte exceeded 0x35
|
|
(e.g. week 46 = 0x46 = 70 > 53), failing setup with "The device does not
|
|
match the ABB Terra AC Modbus register map", and mis-decoded the 11 kW/22 kW
|
|
rated-power codes. Manual TCP add of the charger now completes.
|
|
|
|
-- ETM-Schurig SARL <contact@etm-schurig.eu> Fri, 03 Jul 2026 13:15:00 +0200
|
|
|
|
etm-powersync-plugins-modbus (1.15.2+etm4) trixie; urgency=medium
|
|
|
|
* abbterra: fix TCP manual setup never establishing the connection.
|
|
setupTcpThing() wired all the connection signals but never called
|
|
connectDevice(), so reachableChanged()/initializationFinished() never fired
|
|
and the setup hung until timeout ("Thing setup failed"). Now the connection
|
|
is started when the NetworkDeviceMonitor reports the device online.
|
|
|
|
-- ETM-Schurig SARL <contact@etm-schurig.eu> Fri, 03 Jul 2026 12:55:00 +0200
|
|
|
|
etm-powersync-plugins-modbus (1.15.2+etm3) trixie; urgency=medium
|
|
|
|
* abbterra: disable TCP auto-discovery (createMethods = "user" only) for the
|
|
Terra AC Charger (TCP) thing class. Discovery blind-scans the LAN and blows
|
|
up nymead with a SIGSEGV as soon as any Modbus device answers :502 with an
|
|
exception response — the crash is in the generated reachability handler and
|
|
cannot be fixed from the discovery code alone (two attempts failed). For the
|
|
Waveshare RS485-gateway use case discovery can't determine the slave id
|
|
anyway; the charger must be added manually (address + port + slaveId). This
|
|
unblocks adding the charger and stops the crash loop. The underlying
|
|
generated-code crash is tracked separately.
|
|
|
|
-- ETM-Schurig SARL <contact@etm-schurig.eu> Fri, 03 Jul 2026 12:40:00 +0200
|
|
|
|
etm-powersync-plugins-modbus (1.15.2+etm2) trixie; urgency=medium
|
|
|
|
* abbterra: fix nymead SIGSEGV during ABB Terra AC TCP discovery. On a
|
|
reachability-check exception (e.g. any Modbus device on the LAN answering
|
|
:502 with "illegal data address"), AbbTerraTcpDiscovery::cleanupConnection()
|
|
tore the connection down synchronously from inside the connection's own
|
|
QModbusReply "finished" handler, freeing the in-flight reply that the
|
|
generated code still dereferences at abbterramodbustcpconnection.cpp:2062.
|
|
The teardown is now deferred (Qt::QueuedConnection) and made idempotent.
|
|
* abbterra: restore checkReachableRegister ("serialNumber"), required by the
|
|
libnymea-modbus 1.15 connection-class generator.
|
|
|
|
-- ETM-Schurig SARL <contact@etm-schurig.eu> Fri, 03 Jul 2026 12:00:00 +0200
|
|
|
|
etm-powersync-plugins-modbus (1.15.2+etm1) trixie; urgency=medium
|
|
|
|
* Build 1.15,2
|
|
|
|
-- ETM-Schurig SARL <contact@etm-schurig.eu> Tue, 24 Jun 2026 11:00:00 +0200
|
|
|
|
etm-powersync-plugins-modbus (1.15.0+etm5) trixie; urgency=medium
|
|
|
|
* abbterra: fix RTU setup on slow radio links — trigger initialize() on
|
|
master connectedChanged, not only on reachableChanged (which never fires
|
|
within setup timeout over 433 MHz).
|
|
|
|
-- ETM-Schurig SARL <contact@etm-schurig.eu> Tue, 24 Jun 2026 10:00:00 +0200
|
|
|
|
etm-powersync-plugins-modbus (1.15.0+etm4) trixie; urgency=medium
|
|
|
|
* Correction modbus registers.
|
|
|
|
-- ETM-Schurig SARL <contact@etm-schurig.eu> Fri, 13 Jun 2026 10:00:00 +0200
|
|
|