Skip to content

Commit

Permalink
Handling different nordpool area states
Browse files Browse the repository at this point in the history
  • Loading branch information
fredli74 committed Oct 15, 2024
1 parent ea41d38 commit a5299c0
Showing 1 changed file with 50 additions and 41 deletions.
91 changes: 50 additions & 41 deletions providers/nordpool/nordpool-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,75 +54,84 @@ export class NordpoolAgent extends AbstractAgent {
} = await nordpoolAPI.getPrices(this.deliveryDate.toISODate(), config.AREAS, config.CURRENCY);

const areas: Record<string, GQLUpdatePriceInput> = {};
const areaStates: Record<string, string> = {};

// 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<boolean>[] = [];
for (const [name, update] of Object.entries(areas)) {
if (update.prices.length === 0) {
log(LogLevel.Warning, `No prices for ${name}`);
continue;
}
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
log(LogLevel.Info, `No nordpool prices set for ${this.deliveryDate.toISODate()} yet, will try again next hour`);
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;
}
}
Expand Down

0 comments on commit a5299c0

Please sign in to comment.