Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Publish limits via MQTT #64

Merged
merged 2 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,39 @@
"description": "MQTT meter configuration"
}
]
},
"publish": {
"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": "Publish active control limits"
}
},
"required": [
Expand Down
7 changes: 7 additions & 0 deletions src/coordinator/helpers/inverterController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 { Publish } from './publish.js';

export type SupportedControlTypes = Extract<
ControlType,
Expand Down Expand Up @@ -69,6 +70,7 @@ const defaultValues = {
} as const satisfies Record<ControlType, unknown>;

export class InverterController {
private activeLimitOutput: Publish;
private cachedDerSample = new CappedArrayStack<DerSample>({ limit: 100 });
private cachedSiteSample = new CappedArrayStack<SiteSample>({ limit: 100 });
private logger: Logger;
Expand Down Expand Up @@ -105,6 +107,7 @@ export class InverterController {
inverterConfiguration: InverterConfiguration,
) => Promise<void>;
}) {
this.activeLimitOutput = new Publish({ config });
this.secondsToSample = config.inverterControl.sampleSeconds;
this.controlFrequencyMinimumSeconds =
config.inverterControl.controlFrequencyMinimumSeconds;
Expand Down Expand Up @@ -172,6 +175,10 @@ export class InverterController {

writeActiveControlLimit({ limit: activeInverterControlLimit });

this.activeLimitOutput.onActiveInverterControlLimit({
limit: activeInverterControlLimit,
});

this.controlLimitsCache = {
controlLimitsByLimiter,
activeInverterControlLimit,
Expand Down
29 changes: 29 additions & 0 deletions src/coordinator/helpers/publish.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import mqtt from 'mqtt';
import { type Config } from '../../helpers/config.js';
import { type ActiveInverterControlLimit } from './inverterController.js';

export class Publish {
private mqttClient: mqtt.MqttClient | undefined;

constructor({ config }: { config: Config }) {
if (config.publish?.mqtt) {
this.mqttClient = mqtt.connect(config.publish.mqtt.host, {
username: config.publish.mqtt.username,
password: config.publish.mqtt.password,
});
}
}

onActiveInverterControlLimit({
limit,
}: {
limit: ActiveInverterControlLimit;
}) {
if (this.mqttClient) {
this.mqttClient.publish(
'inverterControlLimit',
JSON.stringify(limit),
);
}
}
}
23 changes: 23 additions & 0 deletions src/helpers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,29 @@ A longer time will smooth out load changes but may result in overshoot.`,
})
.describe('MQTT meter configuration'),
]),
publish: 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('Publish active control limits')
.optional(),
});

export type Config = z.infer<typeof configSchema>;
Expand Down
Loading