UNPKG

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
"use strict"; 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;