From a5299c0d16f5392c2d185f1304299b7a1baadef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Lidstr=C3=B6m?= Date: Tue, 15 Oct 2024 14:26:25 +0200 Subject: [PATCH] Handling different nordpool area states --- providers/nordpool/nordpool-agent.ts | 91 +++++++++++++++------------- 1 file changed, 50 insertions(+), 41 deletions(-) diff --git a/providers/nordpool/nordpool-agent.ts b/providers/nordpool/nordpool-agent.ts index 1894d0d7..ac7ba58a 100644 --- a/providers/nordpool/nordpool-agent.ts +++ b/providers/nordpool/nordpool-agent.ts @@ -54,50 +54,50 @@ export class NordpoolAgent extends AbstractAgent { } = await nordpoolAPI.getPrices(this.deliveryDate.toISODate(), config.AREAS, config.CURRENCY); const areas: Record = {}; + const areaStates: Record = {}; - // populate areas based on final areas + // Build a list of area states for (const stateEntry of res.areaStates) { - if (stateEntry.state === "Final") { - for (const area of stateEntry.areas) { - if (!areas[area]) { - if (this.areaIDmap[area] === undefined) { - const id = uuidv5(`${area}.pricelist`, NORDPOOL_NAMESPACE); - try { - // Check that list exits on server - await this.scClient.getPriceList(id); - } catch { - const list = await this.scClient.newPriceList(`EU.${area}`, true, id); - if (list.id !== id) { - throw "Unable to create price list on server"; - } - } - this.areaIDmap[area] = id; - } - - areas[area] = { - priceListID: this.areaIDmap[area], - prices: [], - }; - } - } + for (const area of stateEntry.areas) { + areaStates[area] = stateEntry.state; + } + if (stateEntry.state !== "Final") { + log(LogLevel.Debug, `Area state not final: ${JSON.stringify(stateEntry)}`); } } - // remap area prices to GQLUpdatePriceInput + // Go through prices and populate updatePriceInputs for (const entry of res.multiAreaEntries) { for (const [area, price] of Object.entries(entry.entryPerArea)) { - if (areas[area]) { - areas[area].prices.push({ - startAt: entry.deliveryStart, - price: price / 1e3, - }); - } else { - log(LogLevel.Debug, `Unknown area ${area}`); + if (!areas[area]) { + if (this.areaIDmap[area] === undefined) { + const id = uuidv5(`${area}.pricelist`, NORDPOOL_NAMESPACE); + try { + // Check that list exits on server + await this.scClient.getPriceList(id); + } catch { + const list = await this.scClient.newPriceList(`EU.${area}`, true, id); + if (list.id !== id) { + throw "Unable to create price list on server"; + } + } + this.areaIDmap[area] = id; + } + areas[area] = { + priceListID: this.areaIDmap[area], + prices: [], + }; } + areas[area].prices.push({ + startAt: entry.deliveryStart, + price: price / 1e3, + }); } } - // Updating prices + // Send updates to server + let allFinal = true; + const serverUpdates: Promise[] = []; for (const [name, update] of Object.entries(areas)) { if (update.prices.length === 0) { log(LogLevel.Warning, `No prices for ${name}`); @@ -105,16 +105,25 @@ export class NordpoolAgent extends AbstractAgent { } log( LogLevel.Info, - `Sending updatePrice for ${name} => ${JSON.stringify(update)}` + `Sending ${areaStates[name].toLowerCase()} updatePrice for ${name} => ${JSON.stringify(update)}` ); - await this.scClient.updatePrice(update); + if (areaStates[name] !== "Final") { + allFinal = false; + } + serverUpdates.push(this.scClient.updatePrice(update)); } + await Promise.all(serverUpdates); - this.deliveryDate = this.deliveryDate.plus({ days: 1 }); - const updatedAt = DateTime.fromISO(res.updatedAt, { zone: "utc" }); - const nextUpdate = (updatedAt.plus({ hours: 22 }).startOf("hour").toMillis() + 60e3); - job.interval = Math.max(60, (nextUpdate - now) / 1e3); - + if (allFinal) { + this.deliveryDate = this.deliveryDate.plus({ days: 1 }); + const updatedAt = DateTime.fromISO(res.updatedAt, { zone: "utc" }); + const nextUpdate = (updatedAt.plus({ hours: 22 }).startOf("hour").toMillis() + 60e3); + log(LogLevel.Info, `All areas were Final, scheduling next update at ${new Date(nextUpdate).toISOString()}`); + job.interval = Math.max(60, (nextUpdate - now) / 1e3); + } else { + log(LogLevel.Info, `Some areas were not Final, retrying in 30 minutes`); + job.interval = 1800; + } } catch (e: any) { if (e instanceof RestClientError && e.code === 204) { // No content = no prices set yet @@ -122,7 +131,7 @@ export class NordpoolAgent extends AbstractAgent { const nextUpdate = (Math.floor(now / 3600e3) + 1) * 3600e3 + 120e3; job.interval = Math.max(60, (nextUpdate - now) / 1e3); } else { - log(LogLevel.Error, `Error fetching prices: ${e.message}, will retry in 15 minutes`); + log(LogLevel.Error, `Error fetching prices: ${e.message}, retrying in 15 minutes`); job.interval = 900; } }