[eebus][WIP] Add EEBus IO add-on (LPC/LPP power limits via item metadata) - #21313
[eebus][WIP] Add EEBus IO add-on (LPC/LPP power limits via item metadata)#21313stamateviorel wants to merge 9 commits into
Conversation
Exposes openHAB as an EEBus Controllable System so a CEM/EMS or smart-meter CLS gateway (§14a EnWG) can pair over SHIP and issue LPC/LPP power limits, delivered as commands onto items tagged eebus="lpc"/"lpp". Backed by OpenMUC's jEEBus SHIP/SPINE (EPL-2.0). Shaped as an IO add-on rather than a binding since LPC/LPP are household-wide singleton limits, not per-device Things - mirrors org.openhab.io.homekit's service-config + item-metadata pattern. Signed-off-by: Stamate Viorel <stamate.viorel@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…ATION too Live-tested against eebus-cbsim: entity.addUseCase(LpcCs) threw immediately because getEntities().iterator().next() picked up the implicit DEVICE_INFORMATION entity Device.build() also adds, not the requested CEM one. Select by type instead. Signed-off-by: Stamate Viorel <stamate.viorel@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Documents what's actually been verified live (SHIP pairing, dynamic entity.addUseCase() negotiation, metadata-driven nominalMax) vs. what hasn't (an accepted active-limit write - blocked on a cbsim simulator bug, not this add-on), and points at the superseded CS-binding mirror. Signed-off-by: Stamate Viorel <stamate.viorel@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
wborn
left a comment
There was a problem hiding this comment.
Thanks for working on this. The overall approach of implementing the Controllable System side as an IO add-on with item metadata looks like a good fit, and it matches the direction discussed in #21211.
I found a few lifecycle/configuration issues that I think should be addressed before this is ready:
- Pairing configuration changes currently do not affect the running SHIP node.
- A full item-registry reload can add LPC/LPP use cases again to an entity that already has them.
- Changes to
nominalMax,failsafeLimit, orfailsafeDurationon an already-bound item are silently ignored. - The LPP
nominalMaxdefault differs from the documented4200 Wdefault.
CI also currently fails because the feature should be named openhab-misc-eebus rather than openhab-io-eebus. There are a couple of smaller cleanup items such as the stale README status/build text and the compiler warnings, but I don't think those need separate review threads.
Matches the io.homekit/io.mcp/io.metrics convention - the feature name follows the addon.xml <type> (misc), not the Maven artifactId's io.* package. Was breaking CI. Signed-off-by: Stamate Viorel <stamate.viorel@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
connectPolicy/trustedSkis/autoAcceptPairing were read once in startNode() and never revisited - requiresRestart() excludes them (by design, they shouldn't need a full SHIP node teardown), but nothing then pushed a later change onto the running ShipCommunication either, so e.g. adding a trusted SKI after boot silently had no effect on the live node. ShipCommunication's with*() methods mutate the instance in place and, per its own bytecode, push straight into the underlying Ship object when one is already connected - confirmed before relying on this, since the earlier SimpleLimitationConfig bug came from trusting a constructor's argument order without checking. Extracted configurePairing() so both startNode() and modified() go through the same path instead of duplicating it. Also: unregister the ReadyTracker in deactivate() (was leaked), and suppress the compiler warning on ShipNodeConfiguration - it's flagged deprecated-for-removal since jEEBus.ship 2.3.0 but no replacement is published in this version yet. Signed-off-by: Stamate Viorel <stamate.viorel@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Two related bugs, both stemming from jeebus.spine having no API to remove a use case once entity.addUseCase() has been called: - A full item-registry reload reset the lpcItemName/lppItemName bookkeeping to null before rescanning, so an item that was still tagged got bound again - entity.addUseCase() a second time for a use case it already had attached. Fix: don't reset the bookkeeping; bind() already no-ops correctly when the same item is still bound, it just needed that state to survive the reload. - Editing nominalMax/failsafeLimit/failsafeDuration on an already-bound item's metadata reached bind(), which also silently no-op'd (same guard) - so the change looked like it should apply but didn't, with no explanation. jeebus.spine has no way to reconfigure an already-registered use case, so this can't actually be applied live; now it logs a warning telling the installer to restart instead of just doing nothing. Added EEBusChangeListenerTest (mocking Entity) asserting addUseCase() is called exactly once per use case across both scenarios - the kind of call-count assertion that would have caught this immediately. Signed-off-by: Stamate Viorel <stamate.viorel@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
The README documented 4200W as the default nominalMax for both LPC and LPP, but LPP's real (intentional) default is 0 - claiming export capacity that was never configured would misreport this installation's real capability to the CEM, same reasoning the original Thing-based binding already used for this default. The code was right, the docs weren't; no test locked in the LPP empty-config case either, so added one alongside the existing LPC one. Also updates the status banner: PR number, test count, and the pairing-settings/restart wording now that they're accurate again. Signed-off-by: Stamate Viorel <stamate.viorel@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
|
thanks for the thorough review, all four fixed:
feature is renamed to openhab-misc-eebus, added a test that mocks Entity and asserts addUseCase() call counts across both bug scenarios, and cleaned up the two compiler warnings you flagged (unused readyService field - now actually used to unregister the tracker on deactivate - and suppressed the ShipNodeConfiguration deprecation since there's no replacement published yet). 18/18 tests pass now. |
…nfiguration ShipNodeConfiguration is @deprecated(forRemoval = true), which ECJ categorizes as "removal", a distinct warning category from plain "deprecation" since Java 9 - the wrong key both left the actual warning unsuppressed AND got itself flagged as an unnecessary annotation. Only showed up building through the full reactor (as CI does via -pl -am), not building the submodule standalone, which is how the CI-only failure got past me building it as I went - confirmed by reproducing the exact CI build command locally before trusting the fix. Signed-off-by: Stamate Viorel <stamate.viorel@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…a -am
Both invisible in a standalone 'mvn package' of this module - only
showed up reproducing CI's actual reactor-scoped build command
(./mvnw verify -pl :org.openhab.io.eebus -am -amd), which is what
finally caught them:
- jackson-annotations was pinned to ${jackson.version} (2.21.4) in
feature.xml, but that Jackson module doesn't publish patch releases
the way jackson-core/databind do - 2.21.4 doesn't exist, only plain
2.21. The reactor's root pom already has a dedicated
${jackson.annotations.version} property for exactly this (used by
several other bundles) - was just using the wrong one.
- bcprov/bcpkix are direct pom.xml deps (embedded into this bundle's
jar via bnd), but bcutil-jdk18on was left as a separate external
feature.xml bundle. It needs org.bouncycastle.asn1 packages that
bcprov/bcpkix used to export as real OSGi bundles - once those two
became embedded/private instead, nothing was left to satisfy that
import. org.openhab.io.homekit embeds all three BouncyCastle jars
together for the same reason; matched that instead of the
inconsistent partial-embed.
Reproduced CI's exact build command locally before pushing this time
(not just a standalone module build) - confirmed BUILD SUCCESS
including the karaf-feature-verification goal, 18/18 tests.
Signed-off-by: Stamate Viorel <stamate.viorel@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Description
lets openhab present itself as an eebus controllable system (ship/spine, via openmuc's jeebus sdk) so a cem/ems or smart-meter cls gateway (§14a enwg in germany) can pair with it and issue lpc/lpp power limits. full backstory in #21211.
shaped as an io add-on instead of a binding per @kaikreuzer's feedback there - lpc/lpp are household-wide limits, not per-device, so there's no real thing to model. instead it's service level config (bind address/port, device id, trusted skis) same as io.homekit, plus eebus="lpc" / eebus="lpp" item metadata to bind a use case to whatever item you want, with nominalmax/failsafelimit/failsafeduration in the metadata config. when a paired cem sends a limit it gets pushed straight onto that item as a command so it plugs into whatever automation you already have.
this only lets openhab accept limits from an external cem/gateway, doesn't let it control other eebus devices like a real wallbox or heat pump - openmuc hasn't published a java sdk for that side yet.
supersedes an earlier thing-based binding prototype (mirror at stamateviorel/openhab-eebus-binding, kept for history, points back here now).
went through the add-ons review checklist (#14694) before pushing this.
Testing
13/13 unit tests pass, checkstyle/spotbugs/spotless/i18n all clean.
still no real eebus hardware or cls gateway involved, tested against meisel2000/eebus-cbsim (built on enbility/eebus-go, same stack evcc uses). pairing, mdns discovery, and spine picking up the lpc use case all work end to end including the dynamic entity.addusecase() registration this add-on relies on (added after the device is built, not at build time), correctly reporting back the nominalmax from the item's metadata. found one real bug doing this - building the device also adds an implicit device_information entity alongside the one i asked for, so the entity has to be picked by type not just taken as the first one.
still haven't gotten an accepted active limit write through to the item - same cbsim heartbeat bug as before, not this add-on's fault as far as i can tell.
opening this as a draft since @kaikreuzer suggested it, agree it shouldn't be called done until someone tests it against a real gateway. happy to leave it open for that.