From 791a5e3917f6d61b4e2d706d59bab3d7c51f2eba Mon Sep 17 00:00:00 2001 From: Long Zheng Date: Wed, 11 Dec 2024 20:49:38 +1100 Subject: [PATCH 1/2] Add support to output active limits to MQTT --- config.schema.json | 33 +++++++++++++++++++ src/coordinator/helpers/activeLimitOutput.ts | 32 ++++++++++++++++++ src/coordinator/helpers/inverterController.ts | 7 ++++ src/helpers/config.ts | 23 +++++++++++++ 4 files changed, 95 insertions(+) create mode 100644 src/coordinator/helpers/activeLimitOutput.ts diff --git a/config.schema.json b/config.schema.json index fa51f1b..257554a 100644 --- a/config.schema.json +++ b/config.schema.json @@ -412,6 +412,39 @@ "description": "MQTT meter configuration" } ] + }, + "outputActiveLimits": { + "type": "object", + "properties": { + "mqtt": { + "type": "object", + "properties": { + "host": { + "type": "string", + "description": "The host of the MQTT broker, including \"mqtt://\"" + }, + "username": { + "type": "string", + "description": "The username for the MQTT broker" + }, + "password": { + "type": "string", + "description": "The password for the MQTT broker" + }, + "topic": { + "type": "string", + "description": "The topic to publish limits" + } + }, + "required": [ + "host", + "topic" + ], + "additionalProperties": false + } + }, + "additionalProperties": false, + "description": "Optionally output active control limits" } }, "required": [ diff --git a/src/coordinator/helpers/activeLimitOutput.ts b/src/coordinator/helpers/activeLimitOutput.ts new file mode 100644 index 0000000..a48f624 --- /dev/null +++ b/src/coordinator/helpers/activeLimitOutput.ts @@ -0,0 +1,32 @@ +import mqtt from 'mqtt'; +import { type Config } from '../../helpers/config.js'; +import { type ActiveInverterControlLimit } from './inverterController.js'; + +export class ActiveLimitOutput { + private mqttClient: mqtt.MqttClient | undefined; + + constructor({ config }: { config: Config }) { + if (config.outputActiveLimits?.mqtt) { + this.mqttClient = mqtt.connect( + config.outputActiveLimits.mqtt.host, + { + username: config.outputActiveLimits.mqtt.username, + password: config.outputActiveLimits.mqtt.password, + }, + ); + } + } + + onActiveInverterControlLimit({ + limit, + }: { + limit: ActiveInverterControlLimit; + }) { + if (this.mqttClient) { + this.mqttClient.publish( + 'inverterControlLimit', + JSON.stringify(limit), + ); + } + } +} diff --git a/src/coordinator/helpers/inverterController.ts b/src/coordinator/helpers/inverterController.ts index 2c6ce3b..1c95ea9 100644 --- a/src/coordinator/helpers/inverterController.ts +++ b/src/coordinator/helpers/inverterController.ts @@ -22,6 +22,7 @@ import { CappedArrayStack } from '../../helpers/cappedArrayStack.js'; import { timeWeightedAverage } from '../../helpers/timeWeightedAverage.js'; import { differenceInSeconds } from 'date-fns'; import { type ControlsModel } from '../../connections/sunspec/models/controls.js'; +import { ActiveLimitOutput } from './activeLimitOutput.js'; export type SupportedControlTypes = Extract< ControlType, @@ -69,6 +70,7 @@ const defaultValues = { } as const satisfies Record; export class InverterController { + private activeLimitOutput: ActiveLimitOutput; private cachedDerSample = new CappedArrayStack({ limit: 100 }); private cachedSiteSample = new CappedArrayStack({ limit: 100 }); private logger: Logger; @@ -105,6 +107,7 @@ export class InverterController { inverterConfiguration: InverterConfiguration, ) => Promise; }) { + this.activeLimitOutput = new ActiveLimitOutput({ config }); this.secondsToSample = config.inverterControl.sampleSeconds; this.controlFrequencyMinimumSeconds = config.inverterControl.controlFrequencyMinimumSeconds; @@ -172,6 +175,10 @@ export class InverterController { writeActiveControlLimit({ limit: activeInverterControlLimit }); + this.activeLimitOutput.onActiveInverterControlLimit({ + limit: activeInverterControlLimit, + }); + this.controlLimitsCache = { controlLimitsByLimiter, activeInverterControlLimit, diff --git a/src/helpers/config.ts b/src/helpers/config.ts index 8019f4a..f0124ed 100644 --- a/src/helpers/config.ts +++ b/src/helpers/config.ts @@ -237,6 +237,29 @@ A longer time will smooth out load changes but may result in overshoot.`, }) .describe('MQTT meter configuration'), ]), + outputActiveLimits: z + .object({ + mqtt: z + .object({ + host: z + .string() + .describe( + 'The host of the MQTT broker, including "mqtt://"', + ), + username: z + .string() + .optional() + .describe('The username for the MQTT broker'), + password: z + .string() + .optional() + .describe('The password for the MQTT broker'), + topic: z.string().describe('The topic to publish limits'), + }) + .optional(), + }) + .describe('Optionally output active control limits') + .optional(), }); export type Config = z.infer; From 4231de6ecf54d979d96eef331cf674b7270dd6bb Mon Sep 17 00:00:00 2001 From: Long Zheng Date: Wed, 11 Dec 2024 20:53:23 +1100 Subject: [PATCH 2/2] Rename to publish --- config.schema.json | 4 ++-- src/coordinator/helpers/inverterController.ts | 6 +++--- .../helpers/{activeLimitOutput.ts => publish.ts} | 15 ++++++--------- src/helpers/config.ts | 4 ++-- 4 files changed, 13 insertions(+), 16 deletions(-) rename src/coordinator/helpers/{activeLimitOutput.ts => publish.ts} (60%) diff --git a/config.schema.json b/config.schema.json index 257554a..ca22c79 100644 --- a/config.schema.json +++ b/config.schema.json @@ -413,7 +413,7 @@ } ] }, - "outputActiveLimits": { + "publish": { "type": "object", "properties": { "mqtt": { @@ -444,7 +444,7 @@ } }, "additionalProperties": false, - "description": "Optionally output active control limits" + "description": "Publish active control limits" } }, "required": [ diff --git a/src/coordinator/helpers/inverterController.ts b/src/coordinator/helpers/inverterController.ts index 1c95ea9..557aca7 100644 --- a/src/coordinator/helpers/inverterController.ts +++ b/src/coordinator/helpers/inverterController.ts @@ -22,7 +22,7 @@ import { CappedArrayStack } from '../../helpers/cappedArrayStack.js'; import { timeWeightedAverage } from '../../helpers/timeWeightedAverage.js'; import { differenceInSeconds } from 'date-fns'; import { type ControlsModel } from '../../connections/sunspec/models/controls.js'; -import { ActiveLimitOutput } from './activeLimitOutput.js'; +import { Publish } from './publish.js'; export type SupportedControlTypes = Extract< ControlType, @@ -70,7 +70,7 @@ const defaultValues = { } as const satisfies Record; export class InverterController { - private activeLimitOutput: ActiveLimitOutput; + private activeLimitOutput: Publish; private cachedDerSample = new CappedArrayStack({ limit: 100 }); private cachedSiteSample = new CappedArrayStack({ limit: 100 }); private logger: Logger; @@ -107,7 +107,7 @@ export class InverterController { inverterConfiguration: InverterConfiguration, ) => Promise; }) { - this.activeLimitOutput = new ActiveLimitOutput({ config }); + this.activeLimitOutput = new Publish({ config }); this.secondsToSample = config.inverterControl.sampleSeconds; this.controlFrequencyMinimumSeconds = config.inverterControl.controlFrequencyMinimumSeconds; diff --git a/src/coordinator/helpers/activeLimitOutput.ts b/src/coordinator/helpers/publish.ts similarity index 60% rename from src/coordinator/helpers/activeLimitOutput.ts rename to src/coordinator/helpers/publish.ts index a48f624..08a7893 100644 --- a/src/coordinator/helpers/activeLimitOutput.ts +++ b/src/coordinator/helpers/publish.ts @@ -2,18 +2,15 @@ import mqtt from 'mqtt'; import { type Config } from '../../helpers/config.js'; import { type ActiveInverterControlLimit } from './inverterController.js'; -export class ActiveLimitOutput { +export class Publish { private mqttClient: mqtt.MqttClient | undefined; constructor({ config }: { config: Config }) { - if (config.outputActiveLimits?.mqtt) { - this.mqttClient = mqtt.connect( - config.outputActiveLimits.mqtt.host, - { - username: config.outputActiveLimits.mqtt.username, - password: config.outputActiveLimits.mqtt.password, - }, - ); + if (config.publish?.mqtt) { + this.mqttClient = mqtt.connect(config.publish.mqtt.host, { + username: config.publish.mqtt.username, + password: config.publish.mqtt.password, + }); } } diff --git a/src/helpers/config.ts b/src/helpers/config.ts index f0124ed..fd80655 100644 --- a/src/helpers/config.ts +++ b/src/helpers/config.ts @@ -237,7 +237,7 @@ A longer time will smooth out load changes but may result in overshoot.`, }) .describe('MQTT meter configuration'), ]), - outputActiveLimits: z + publish: z .object({ mqtt: z .object({ @@ -258,7 +258,7 @@ A longer time will smooth out load changes but may result in overshoot.`, }) .optional(), }) - .describe('Optionally output active control limits') + .describe('Publish active control limits') .optional(), });