Repository navigation
Conversation
JAX-RS proxy and wire records for creating, reading, replacing and cancelling GOPACS orders and listing their settlements. Status and order type stay strings so new values in the draft API do not break deserialisation.
Announcement inputs are read-only and meant to be filled through attribute links from an EmsGOPACSAsset, so the Distro integration does not depend on the GOPACS handlers. Order type and quantity are pre-filled by the handler and can be overridden; price, confirm and cancel are set by the operator. The existing day-ahead panels are renamed so both groups read clearly in the asset view.
Pre-fills order type and quantity from the linked announcement: the EAN effectivity category picks the side, and the batteries under the parent optimisation asset size a constant power that their state of charge can hold for the whole window. On operator confirmation the order is posted to Distro; a price change replaces open orders, a closed announcement or the cancel flag cancels them, and a poll tracks status until a final one, recording the trades of settled orders. Tokens come from OpenRemote's OAuth filter, which caches and refreshes the client-credentials token.
One handler per EmsDistroEnergyAsset while gopacsEnabled is true, reconciled from both the persistence route and attribute events under a lock, independent of the day-ahead handler. Other gopacs* attribute events are forwarded to the running handler.
Unit spec for the effectivity-to-side mapping, battery sizing, expiration and the attribute-driven create/replace/cancel/poll flows; WireMock spec for the OAuth token call, bearer reuse and wire format; service spec for the gopacsEnabled reconcile.
Configuration, the attribute links from EmsGOPACSAsset, order sizing, the order lifecycle and the new tests. Also replace the made-up effectivity example in the GOPACS docs with a real category.
Track an order as PENDING before posting it, so a create that times out after Distro accepted it is still polled, cancelled and settled. Only a 4xx untracks it again. Store a polled order before fetching its settlements, so a failed fetch is retried next poll without repeating the STATUS entry. Read every settlements page. Skip the suggestion when the batteries cannot hold the 100 kW minimum. Drop queued work once the handler is undeployed and close the client only after a running order action has finished.
Day-ahead stays on the left, so the two Distro features no longer interleave on the asset page.
Operators work in these two panels, so they sit next to the day-ahead panels while configuration, status and history stay on the right.
Turning gopacsEnabled off or deleting the asset stopped polling but left PENDING and SUBMITTED orders live at Distro, where they could still be matched with nothing tracking them. Both now cancel the open orders before closing the client. A manager stop still leaves them in place, since the next start restores and keeps tracking them.
The updated Distro spec takes at most one decimal for the quantity in MW and two for the price, requires a price of 0 or more, needs the order to expire at least 15 minutes before start, and only lets SUBMITTED orders be replaced. Round an operator-entered quantity down to 100 kW steps and the price to cents. Refuse a negative price, on confirm and on a price change, and refuse a window that starts within 15 minutes. Replace only the SUBMITTED orders of the announcement.
GOPACS no longer takes bids for an announcement once its bid validity end has passed. Such an order went out with Distro's default expiry and stayed live without any chance to help. Refuse it when the validity end is known.
The updated Distro spec says the settlements endpoint is not implemented yet. A settled order whose trade fetch failed stayed tracked for a retry, so it would have been polled every five minutes forever. Record the failure as SETTLEMENTS_FAILED and drop the order instead.
The handler built a pending GopacsOrder from a request and a replace request from an order by hand. GopacsOrder.pending(request) and toRequest(price) now own those copies.
Routing every gopacs* attribute also sent the handler's own writes (orders, history, last sync, the pre-filled type and quantity) back to it, and each queued a task that did nothing. Route on the explicit DistroGopacsHandler.INPUTS set instead.
Build the three updateSuggestion log messages with String.format instead of long string concatenations.
An undeploy less than a second after a confirm or cancel skipped the delayed reset, leaving the flag true. Setting it to true again after re-enabling was then an unchanged value and was ignored. Deploy now resets either flag that is still true.
Log the handler config at deploy (without the secret), every changed input at FINE, and confirms, cancels, placed and replaced orders and status changes at INFO. Warn when a flag is ignored because it is already true or because no handler is running for the asset.
A bare HTTP 403 does not say whether the tenant, the IP whitelist or the URL is wrong. Log Distro's error body, cut to 500 characters, and record it in the order history. HTTP errors are logged without the stack trace, which adds nothing for them.
gopacsOrderType was free text, so an operator could type anything and only learn at confirm time that it was refused. An enum value type renders as a dropdown in the manager UI. The handler now works with the enum and only turns it into a string for the Distro request.
placeOrder built the refusal reason through a long else-if chain. The checks now live in a static validateInput that returns early, so placeOrder only reads the attributes, refuses or sends. The quarter-hour alignment check is gone: the window is linked from the GOPACS announcement and is read-only, so it is always aligned. The separate rounding log is folded into the Placing log, which now also shows the quantity the operator entered.
gopacsOrderPrice is now a POSITIVE_NUMBER (min 0). OpenRemote validates every attribute event against the value constraints, from the UI as well as from rules and links, so a negative price never reaches the handler. The handler's own negative-price checks on create and replace are removed.
CI runs spotlessCheck, which failed on both test files. Formatting only.
Distro confirmed the settlement endpoints go live shortly and that the trades are available as soon as an order is SETTLED. The Javadoc and docs no longer say the endpoints are missing. Behaviour is unchanged: one fetch per settled order, no retry.
The Distro GOPACS order handler reads the announcement from six read-only gopacs* inputs, but nothing in the extension filled them: each deployment had to add attribute links from the EmsGOPACSAsset by hand and copy the current values once. EmsOptimisationService now copies contractedEAN and the redispatch announcement attributes to every EmsDistroEnergyAsset that shares the GOPACS asset's parent. It does so on a change of one of those GOPACS attributes, on a save of either asset, and at start. Only inputs that differ are written, so the redispatch poller rewriting the same announcement does not rewrite the Distro asset on every poll. Nothing is copied while a parent has more than one GOPACS asset.
The Distro asset no longer needs attribute links from the GOPACS asset: EmsOptimisationService copies the announcement to the Distro asset under the same parent. The setup steps, attribute table and workflow diagram now describe the copy.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Closes #133. Part of openremote/denhaag#209, which stays open until the orders are tested on production.
Adds
DistroGopacsHandler, which places GOPACS redispatch orders through Distro Energy's GOPACS Connector API. It is switched on perEmsDistroEnergyAssetwithgopacsEnabled.EmsOptimisationServicecopies the redispatch announcement from theEmsGOPACSAssetto everyEmsDistroEnergyAssetunder the same parent, so a deployment needs no attribute links and the GOPACS and Distro handlers stay independent.The handler pre-fills order type and quantity from the announcement and the batteries. The operator sets a price and confirms, and nothing is ordered automatically. After that it polls the order status, replaces open orders when the price changes, and cancels them when the announcement closes, on a manual cancel, or when
gopacsEnabledis turned off or the asset is deleted. Setup is described inems/docs/DistroEnergyIntegration.md.