From 983242e07944e791efa4879e301239c12d0250d7 Mon Sep 17 00:00:00 2001 From: Long Zheng Date: Tue, 3 Sep 2024 17:40:15 +1000 Subject: [PATCH] Add more logging --- src/helpers/influxdb.ts | 39 +++++++++++++++++ src/limiters/amber/index.test.ts | 58 +------------------------ src/limiters/amber/index.ts | 73 ++++++++++++++++---------------- src/limiters/fixed/index.ts | 7 ++- src/limiters/sep2/index.ts | 7 ++- 5 files changed, 89 insertions(+), 95 deletions(-) diff --git a/src/helpers/influxdb.ts b/src/helpers/influxdb.ts index 53e3cd1..2827918 100644 --- a/src/helpers/influxdb.ts +++ b/src/helpers/influxdb.ts @@ -7,6 +7,7 @@ import type { FallbackControl } from '../sep2/helpers/derControls'; import { numberWithPow10 } from './number'; import type { SiteMonitoringSample } from '../coordinator/helpers/siteMonitoring'; import type { DerMonitoringSample } from '../coordinator/helpers/derMonitoring'; +import type { InverterControlLimit } from '../coordinator/helpers/inverterController'; const influxDB = new InfluxDB({ url: `http://influxdb:${process.env['INFLUXDB_PORT']}`, @@ -308,3 +309,41 @@ export function writeInverterControllerPoints({ ), ]); } + +export function writeAmberPrice(number: number | undefined) { + influxDbWriteApi.writePoints( + [ + number !== undefined + ? new Point('amber').floatField('price', number) + : null, + ].filter((point) => point !== null), + ); +} + +export function writeControlLimit({ + limit, + name, +}: { + limit: InverterControlLimit; + name: string; +}) { + const point = new Point('controlLimit').tag('name', name); + + if (limit.opModConnect !== undefined) { + point.booleanField('opModConnect', limit.opModConnect); + } + + if (limit.opModEnergize !== undefined) { + point.booleanField('opModEnergize', limit.opModEnergize); + } + + if (limit.opModExpLimW !== undefined) { + point.floatField('opModExpLimW', limit.opModExpLimW); + } + + if (limit.opModGenLimW !== undefined) { + point.floatField('opModGenLimW', limit.opModGenLimW); + } + + influxDbWriteApi.writePoint(point); +} diff --git a/src/limiters/amber/index.test.ts b/src/limiters/amber/index.test.ts index 0d0b04a..f75dc88 100644 --- a/src/limiters/amber/index.test.ts +++ b/src/limiters/amber/index.test.ts @@ -8,7 +8,7 @@ import { it, vi, } from 'vitest'; -import { AmberLimiter, getControlLimitFromIntervals } from '.'; +import { AmberLimiter } from '.'; import { setupServer } from 'msw/node'; import { HttpResponse, http } from 'msw'; @@ -133,59 +133,3 @@ describe('AmberControlLimit', () => { }); }); }); - -describe('getControlLimitFromIntervals', () => { - it('should return correct control limit with active interval', () => { - vi.setSystemTime(new Date('2024-01-01T00:00:01Z')); - - const feedInIntervals = [ - { - start: new Date('2024-01-01T00:00:00Z'), - end: new Date('2024-01-01T00:30:00Z'), - price: -60.0, - }, - { - start: new Date('2024-01-01T00:30:00Z'), - end: new Date('2024-01-01T01:00:00Z'), - price: 30.0, - }, - ]; - - const result = getControlLimitFromIntervals(feedInIntervals); - - expect(result).toEqual({ - opModConnect: undefined, - opModEnergize: undefined, - opModExpLimW: 0, - opModGenLimW: undefined, - }); - }); - - it('should return correct control limit when no applicable intervals', () => { - // january - vi.setSystemTime(new Date('2024-01-01T00:00:01Z')); - - // all future intervals - const feedInIntervals = [ - { - start: new Date('2024-02-01T00:00:00Z'), - end: new Date('2024-02-01T00:30:00Z'), - price: -60.0, - }, - { - start: new Date('2024-02-01T00:30:00Z'), - end: new Date('2024-02-01T01:00:00Z'), - price: 30.0, - }, - ]; - - const result = getControlLimitFromIntervals(feedInIntervals); - - expect(result).toEqual({ - opModConnect: undefined, - opModEnergize: undefined, - opModExpLimW: undefined, - opModGenLimW: undefined, - }); - }); -}); diff --git a/src/limiters/amber/index.ts b/src/limiters/amber/index.ts index 21a037c..02ac43f 100644 --- a/src/limiters/amber/index.ts +++ b/src/limiters/amber/index.ts @@ -5,6 +5,7 @@ import type { LimiterType } from '../../coordinator/helpers/limiter'; import type { InverterControlLimit } from '../../coordinator/helpers/inverterController'; import type { Logger } from 'pino'; import { logger as pinoLogger } from '../../helpers/logger'; +import { writeAmberPrice, writeControlLimit } from '../../helpers/influxdb'; type Interval = { start: Date; @@ -32,7 +33,29 @@ export class AmberLimiter implements LimiterType { } getInverterControlLimit(): InverterControlLimit { - return getControlLimitFromIntervals(this.feedInIntervals); + const price = this.getCurrentPrice(); + + const limit = + price && price < 0 + ? { + // if feed in price is negative, limit export to 0 + opModConnect: undefined, + opModEnergize: undefined, + opModExpLimW: 0, + opModGenLimW: undefined, + } + : { + // can't find current interval, assume export is fine + // if feed in price is positive, export is fine + opModConnect: undefined, + opModEnergize: undefined, + opModExpLimW: undefined, + opModGenLimW: undefined, + }; + + writeControlLimit({ limit, name: 'amber' }); + + return limit; } private async getSiteFeedInPrices() { @@ -86,42 +109,20 @@ export class AmberLimiter implements LimiterType { ); } } -} -export function getControlLimitFromIntervals( - feedInIntervals: Interval[], -): InverterControlLimit { - // find current feed in price - const now = new Date(); - const currentInterval = feedInIntervals.find( - (interval) => interval.start <= now && now < interval.end, - ); - - // can't find current interval, assume export is fine - if (!currentInterval) { - return { - opModConnect: undefined, - opModEnergize: undefined, - opModExpLimW: undefined, - opModGenLimW: undefined, - }; - } + private getCurrentPrice() { + // find current feed in price + const now = new Date(); + const currentInterval = this.feedInIntervals.find( + (interval) => interval.start <= now && now < interval.end, + ); - // if feed in price is positive, export is fine - if (currentInterval.price >= 0) { - return { - opModConnect: undefined, - opModEnergize: undefined, - opModExpLimW: undefined, - opModGenLimW: undefined, - }; - } + this.logger.trace({ currentInterval }, 'Current interval '); + + const currentPrice = currentInterval?.price; - // if feed in price is negative, limit export to 0 - return { - opModConnect: undefined, - opModEnergize: undefined, - opModExpLimW: 0, - opModGenLimW: undefined, - }; + writeAmberPrice(currentPrice); + + return currentPrice; + } } diff --git a/src/limiters/fixed/index.ts b/src/limiters/fixed/index.ts index 7200657..9de077e 100644 --- a/src/limiters/fixed/index.ts +++ b/src/limiters/fixed/index.ts @@ -1,6 +1,7 @@ import type { InverterControlLimit } from '../../coordinator/helpers/inverterController'; import type { LimiterType } from '../../coordinator/helpers/limiter'; import type { Config } from '../../helpers/config'; +import { writeControlLimit } from '../../helpers/influxdb'; type FixedLimiterConfig = NonNullable; @@ -12,11 +13,15 @@ export class FixedLimiter implements LimiterType { } getInverterControlLimit(): InverterControlLimit { - return { + const limit = { opModConnect: this.config.connect, opModEnergize: this.config.connect, opModExpLimW: this.config.exportLimitWatts, opModGenLimW: this.config.generationLimitWatts, }; + + writeControlLimit({ limit, name: 'fixed' }); + + return limit; } } diff --git a/src/limiters/sep2/index.ts b/src/limiters/sep2/index.ts index d0daf81..5c41426 100644 --- a/src/limiters/sep2/index.ts +++ b/src/limiters/sep2/index.ts @@ -11,6 +11,7 @@ import type { DerControlsHelperChangedData } from '../../sep2/helpers/derControl import EventEmitter from 'events'; import type { LimiterType } from '../../coordinator/helpers/limiter'; import { numberWithPow10 } from '../../helpers/number'; +import { writeControlLimit } from '../../helpers/influxdb'; export class Sep2Limiter extends EventEmitter<{ @@ -72,7 +73,7 @@ export class Sep2Limiter const opModGenLimW = this.schedulerByControlType.opModGenLimW.getActiveScheduleDerControlBaseValue(); - return { + const limit = { opModExpLimW: opModExpLimW ? numberWithPow10(opModExpLimW.value, opModExpLimW.multiplier) : undefined, @@ -84,5 +85,9 @@ export class Sep2Limiter opModConnect: this.schedulerByControlType.opModConnect.getActiveScheduleDerControlBaseValue(), }; + + writeControlLimit({ limit, name: 'sep2' }); + + return limit; } }