node-red-contrib-genetic-charging-strategy
Version:
A module for Node-RED that adds a battery charging strategy to node-red-contrib-power-saver. It uses genetic algorithms to find the best schedule
112 lines (111 loc) • 4.89 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateBatteryChargingStrategy = void 0;
const geneticalgorithm_1 = require("./geneticalgorithm");
const fitness_1 = require("./fitness");
const population_1 = require("./population");
const mutation_1 = require("./mutation");
const crossover_1 = require("./crossover");
const schedule_1 = require("./schedule");
const moment_1 = __importDefault(require("moment"));
const toSchedule = (props, phenotype) => {
var _a, _b, _c, _d, _e, _f;
const { input } = props;
const activityToName = (activity) => {
switch (activity) {
case -1:
return 'discharging';
case 1:
return 'charging';
default:
return 'idle';
}
};
const schedule = [];
const periodStart = moment_1.default.unix(input[0].start);
for (const period of (0, fitness_1.allPeriodsGenerator)(props, phenotype)) {
if (period.duration != undefined && period.duration <= 0) {
continue;
}
const lastPeriod = schedule.at(-1);
if (lastPeriod && lastPeriod.activity === period.activity) {
lastPeriod.duration += (_a = period.duration) !== null && _a !== void 0 ? _a : 0;
lastPeriod.cost += (_b = period.cost) !== null && _b !== void 0 ? _b : 0;
lastPeriod.charge += (_c = period.charge) !== null && _c !== void 0 ? _c : 0;
}
else {
schedule.push({
start: periodStart.clone().add(period.start, 'm').toISOString(),
activity: period.activity,
name: activityToName(period.activity),
duration: (_d = period.duration) !== null && _d !== void 0 ? _d : 0,
cost: (_e = period.cost) !== null && _e !== void 0 ? _e : 0,
charge: (_f = period.charge) !== null && _f !== void 0 ? _f : 0,
});
}
}
return schedule;
};
const mergeInput = (config) => {
const { averageConsumption, averageProduction, priceData, consumptionForecast, productionForecast, } = config;
const startOfHour = (0, moment_1.default)().startOf('hour').unix();
return priceData
.filter((v) => v.start >= startOfHour)
.map((v) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
return {
start: v.start,
importPrice: (_a = v.importPrice) !== null && _a !== void 0 ? _a : v.value,
exportPrice: (_c = (_b = v.exportPrice) !== null && _b !== void 0 ? _b : v.importPrice) !== null && _c !== void 0 ? _c : v.value,
consumption: (_f = (_e = (_d = consumptionForecast.find((c) => c.start === v.start)) === null || _d === void 0 ? void 0 : _d.value) !== null && _e !== void 0 ? _e : averageConsumption) !== null && _f !== void 0 ? _f : 0,
production: (_j = (_h = (_g = productionForecast.find((p) => p.start === v.start)) === null || _g === void 0 ? void 0 : _g.value) !== null && _h !== void 0 ? _h : averageProduction) !== null && _j !== void 0 ? _j : 0,
};
});
};
const calculateBatteryChargingStrategy = (config) => {
var _a;
const { generations } = config;
const input = mergeInput(config);
if (input === undefined || input.length === 0)
return;
const props = {
...config,
input,
totalDuration: input.length * 60,
batteryIdleLoss: (_a = config.batteryIdleLoss) !== null && _a !== void 0 ? _a : 0,
};
const options = {
mutationFunction: (0, mutation_1.mutationFunction)(props),
crossoverFunction: (0, crossover_1.crossoverFunction)(props),
fitnessFunction: (0, fitness_1.fitnessFunction)(props),
population: (0, population_1.populationFunction)(props),
};
const geneticAlgorithm = (0, geneticalgorithm_1.geneticAlgorithmConstructor)(options);
for (let i = 0; i < generations; i += 1) {
geneticAlgorithm.evolve();
}
const best = geneticAlgorithm.best();
const noBattery = {
periods: new schedule_1.DoublyLinkedList().insertBack({
start: 0,
activity: 0,
}),
excessPvEnergyUse: 0,
};
return {
best: {
schedule: toSchedule(props, best),
excessPvEnergyUse: best.excessPvEnergyUse,
cost: (0, fitness_1.cost)((0, fitness_1.allPeriods)(props, best)),
},
noBattery: {
schedule: toSchedule(props, noBattery),
excessPvEnergyUse: noBattery.excessPvEnergyUse,
cost: (0, fitness_1.cost)((0, fitness_1.allPeriods)(props, noBattery)),
},
};
};
exports.calculateBatteryChargingStrategy = calculateBatteryChargingStrategy;