2179 lines
98 KiB
C++
2179 lines
98 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
*
|
|
* Copyright (C) 2013 - 2024, nymea GmbH
|
|
* Copyright (C) 2024 - 2025, chargebyte austria GmbH
|
|
*
|
|
* This file is part of nymea-energy-plugin-nymea.
|
|
*
|
|
* nymea-energy-plugin-nymea.s free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* nymea-energy-plugin-nymea.s distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with nymea-energy-plugin-nymea. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include "simulation.h"
|
|
|
|
#include <hardware/electricity.h>
|
|
#include <servers/mocktcpserver.h>
|
|
#include <experiences/experiencemanager.h>
|
|
#include <experiences/experienceplugin.h>
|
|
|
|
using namespace nymeaserver;
|
|
|
|
#include "../../../energyplugin/smartchargingmanager.h"
|
|
#include "../../mocks/spotmarketprovider/spotmarketdataprovidermock.h"
|
|
|
|
#include <QHash>
|
|
#include <QtMath>
|
|
#include <QtGlobal>
|
|
#include <QProcess>
|
|
#include <QDateTime>
|
|
#include <QSignalSpy>
|
|
#include <QProcessEnvironment>
|
|
|
|
#include <nymeacore.h>
|
|
|
|
#include "simulationtestpoint.h"
|
|
|
|
void Simulation::run_data()
|
|
{
|
|
// Simulation infos
|
|
QTest::addColumn<QString>("simulationName");
|
|
QTest::addColumn<QString>("simulationTitle");
|
|
QTest::addColumn<QString>("databaseName");
|
|
QTest::addColumn<QDateTime>("simulationStart");
|
|
QTest::addColumn<ChargerPlugEvents>("plugEvents");
|
|
QTest::addColumn<int>("simulationHours");
|
|
QTest::addColumn<EnergyLogs::SampleRate>("sampleRate");
|
|
QTest::addColumn<double>("productionScaling");
|
|
QTest::addColumn<int>("detailsStepStart");
|
|
QTest::addColumn<int>("detailsStepStop");
|
|
QTest::addColumn<DetailsStepList>("detailsStepList");
|
|
|
|
// Houshold info
|
|
QTest::addColumn<int>("phasePowerLimit");
|
|
QTest::addColumn<bool>("spotMarketEnabled");
|
|
QTest::addColumn<QString>("spotMarketResourceData");
|
|
QTest::addColumn<double>("acquisitionTolerance");
|
|
QTest::addColumn<double>("batteryLevelConsideration");
|
|
|
|
// ChargingInfo
|
|
QTest::addColumn<double>("targetPercentage");
|
|
QTest::addColumn<QDateTime>("targetDateTime");
|
|
QTest::addColumn<QString>("chargingMode");
|
|
QTest::addColumn<int>("carBatteryLevel");
|
|
QTest::addColumn<int>("dailySpotMarketPercentage");
|
|
|
|
// Car information and states
|
|
QTest::addColumn<int>("carCapacity");
|
|
QTest::addColumn<int>("carMinChargingCurrent");
|
|
QTest::addColumn<int>("carPhaseCount");
|
|
|
|
// Energy storage information and states
|
|
QTest::addColumn<bool>("energyStorageAvailable");
|
|
QTest::addColumn<int>("energyStorageCapacity");
|
|
QTest::addColumn<double>("energyStorageMaxChargingPower");
|
|
QTest::addColumn<double>("energyStorageMaxDischargingPower");
|
|
QTest::addColumn<double>("energyStorageInitialBatteyLevel");
|
|
|
|
// Charger initial states
|
|
QTest::addColumn<bool>("chargerConnected");
|
|
QTest::addColumn<bool>("chargerPower");
|
|
QTest::addColumn<QString>("chargerPhases");
|
|
QTest::addColumn<bool>("canSwitchPhaseCount");
|
|
QTest::addColumn<int>("chargerMaxChargingCurrent");
|
|
QTest::addColumn<int>("chargerMaxChargingCurrentMaxValue");
|
|
|
|
QTest::addColumn<SimulationIterationTest>("iterationTest");
|
|
|
|
bool runAllSimulations = true;
|
|
|
|
bool runSpotmarketSimulation = runAllSimulations;
|
|
bool run1PhaseSimulations = runAllSimulations;
|
|
bool run2PhaseSimulations = runAllSimulations;
|
|
bool run3PhaseSimulations = runAllSimulations;
|
|
bool runPhaseSwitchingSimulations = runAllSimulations;
|
|
|
|
// Simulations
|
|
if (runSpotmarketSimulation)
|
|
QTest::newRow("Spotmarket only")
|
|
|
|
/* Simulation info */
|
|
|
|
<< "simulation-spotmarket-only-1-phase-16A" // simulationName
|
|
<< "Simulation (1 phase, charger 16A max, only spot market)" // simulationTitle
|
|
<< ":/databases/2022-08-12-kostal-energylogs.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 8, 14), QTime(0,0,0)) // simulationStart (UTC)
|
|
|
|
<< ChargerPlugEvents( { ChargerPlugEvent(EnergyTestBase::utcDateTime(QDate(2022, 8, 14), QTime(7,0,0)), false),
|
|
ChargerPlugEvent(EnergyTestBase::utcDateTime(QDate(2022, 8, 14), QTime(17,30,0)), true),
|
|
ChargerPlugEvent(EnergyTestBase::utcDateTime(QDate(2022, 8, 15), QTime(7,0,0)), false),
|
|
ChargerPlugEvent(EnergyTestBase::utcDateTime(QDate(2022, 8, 15), QTime(17,0,0)), true)
|
|
}) // pluggedInTime (UTC)
|
|
|
|
<< 48 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 0.0 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 0 // detailsStepStop
|
|
<< DetailsStepList() // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< true // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 8, 15), QTime(22,0,0)) // targetDateTime
|
|
<< "ChargingModeEco" // chargingMode
|
|
<< 20 // carBatteryLevel
|
|
<< 20 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 1 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< false // energyStorageAvailable
|
|
<< 0 // energyStorageCapacity
|
|
<< 0.0 // energyStorageMaxChargingPower
|
|
<< 0.0 // energyStorageMaxDischargingPower
|
|
<< 50.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< false // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 16 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
0, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 20)
|
|
}
|
|
},
|
|
{
|
|
250, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
}
|
|
},
|
|
{
|
|
500, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
}
|
|
},
|
|
{
|
|
1440, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 40) // Should have charged 20% in one day
|
|
}
|
|
},
|
|
{
|
|
2800, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
}
|
|
},
|
|
{
|
|
2880, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 60) // Should have charged 20% in one day
|
|
}
|
|
}
|
|
} );
|
|
|
|
if (runSpotmarketSimulation)
|
|
QTest::newRow("Spotmarket and PV")
|
|
|
|
/* Simulation info */
|
|
|
|
<< "simulation-spotmarket-and-pv-1-phase-16A" // simulationName
|
|
<< "Simulation (1 phase, charger 16A max, spot market and PV)" // simulationTitle
|
|
<< ":/databases/2022-08-12-kostal-energylogs.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 8, 14), QTime(0,0,0)) // simulationStart (UTC)
|
|
<< ChargerPlugEvents()
|
|
|
|
<< 48 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 0.35 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 0 // detailsStepStop
|
|
<< DetailsStepList() // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< true // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 8, 15), QTime(22,0,0)) // targetDateTime
|
|
<< "ChargingModeEco" // chargingMode
|
|
<< 20 // carBatteryLevel
|
|
<< 20 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 1 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< false // energyStorageAvailable
|
|
<< 0 // energyStorageCapacity
|
|
<< 0.0 // energyStorageMaxChargingPower
|
|
<< 0.0 // energyStorageMaxDischargingPower
|
|
<< 50.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< false // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 16 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
0, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 20)
|
|
}
|
|
},
|
|
{
|
|
250, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
500, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
580, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
750, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
780, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
810, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
1400, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
2000, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 46) // Should be at least 20% more than the day before...
|
|
}
|
|
},
|
|
{
|
|
2250, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
}
|
|
},
|
|
{
|
|
2750, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
}
|
|
}
|
|
} );
|
|
|
|
if (runSpotmarketSimulation)
|
|
QTest::newRow("Spotmarket with target time")
|
|
|
|
/* Simulation info */
|
|
|
|
<< "simulation-spotmarket-only-with-targettime-1-phase-16A" // simulationName
|
|
<< "Simulation (1 phase, charger 16A max, only spot market with target time)" // simulationTitle
|
|
<< ":/databases/2022-08-12-kostal-energylogs.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 8, 14), QTime(0,0,0)) // simulationStart (UTC)
|
|
<< ChargerPlugEvents() // Car plug events
|
|
|
|
<< 48 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 0.0 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 0 // detailsStepStop
|
|
<< DetailsStepList() // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< true // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 8, 15), QTime(22,0,0)) // targetDateTime
|
|
<< "ChargingModeEcoWithTargetTime" // chargingMode
|
|
<< 20 // carBatteryLevel
|
|
<< 0 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 1 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< false // energyStorageAvailable
|
|
<< 0 // energyStorageCapacity
|
|
<< 0.0 // energyStorageMaxChargingPower
|
|
<< 0.0 // energyStorageMaxDischargingPower
|
|
<< 50.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< false // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 16 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
0, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 20)
|
|
}
|
|
},
|
|
{
|
|
700, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
1200, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
1400, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
1550, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
1700, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
2760, { // 22:00
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 100)
|
|
}
|
|
}
|
|
} );
|
|
|
|
|
|
if (runSpotmarketSimulation)
|
|
QTest::newRow("Spotmarket only with target time")
|
|
|
|
/* Simulation info */
|
|
|
|
<< "simulation-spotmarket-only-with-targettime-1-day-1-phase-16A" // simulationName
|
|
<< "Simulation (1 phase, charger 16A max, only spot market with target time single day)" // simulationTitle
|
|
<< ":/databases/2022-08-12-kostal-energylogs.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 8, 14), QTime(0, 0, 0)) // simulationStart (UTC)
|
|
<< ChargerPlugEvents()
|
|
|
|
<< 32 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 0.0 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 0 // detailsStepStop
|
|
<< DetailsStepList() // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< true // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 8, 15), QTime(07, 0, 0)) // targetDateTime
|
|
<< "ChargingModeEcoWithTargetTime" // chargingMode
|
|
<< 50 // carBatteryLevel
|
|
<< 0 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 1 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< false // energyStorageAvailable
|
|
<< 0 // energyStorageCapacity
|
|
<< 0.0 // energyStorageMaxChargingPower
|
|
<< 0.0 // energyStorageMaxDischargingPower
|
|
<< 50.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< false // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 16 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
0, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 50)
|
|
}
|
|
},
|
|
{
|
|
250, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 61)
|
|
}
|
|
},
|
|
{
|
|
500, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
}
|
|
},
|
|
{
|
|
1400, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
}
|
|
}
|
|
});
|
|
|
|
if (run1PhaseSimulations)
|
|
QTest::newRow("Default")
|
|
/* Simulation info */
|
|
<< "simulation-1-phase-32A" // simulationName
|
|
<< "Simulation (1 phase, charger 32A max, target 22:00 100%" // simulationTitle
|
|
<< ":/databases/2022-06-28-energylogs-micha.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(6,0,0)) // simulationStart (UTC)
|
|
<< ChargerPlugEvents() // pluggedInTime (UTC)
|
|
<< 18 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 20.0 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 0 // detailsStepStop
|
|
<< DetailsStepList() // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< false // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(22,0,0)) // targetDateTime
|
|
<< "ChargingModeEcoWithTargetTime" // chargingMode
|
|
<< 40 // carBatteryLevel
|
|
<< 0 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 1 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< false // energyStorageAvailable
|
|
<< 0 // energyStorageCapacity
|
|
<< 0.0 // energyStorageMaxChargingPower
|
|
<< 0.0 // energyStorageMaxDischargingPower
|
|
<< 50.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< false // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 32 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
0, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 40)
|
|
}
|
|
},
|
|
{
|
|
163, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
170, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 9),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
444, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 7) ,
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
520, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6) ,
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 80)
|
|
}
|
|
},
|
|
{
|
|
700, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6) ,
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 85)
|
|
}
|
|
},
|
|
{
|
|
900, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 30) ,
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 88)
|
|
}
|
|
},
|
|
{
|
|
960, { // 22:00
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 30) ,
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 100)
|
|
}
|
|
}
|
|
} );
|
|
|
|
if (run1PhaseSimulations)
|
|
QTest::newRow("Default")
|
|
/* Simulation info */
|
|
<< "simulation-1-phase-16A" // simulationName
|
|
<< "Simulation (1 phase, charger 16A max, target 22:00 100%)" // simulationTitle
|
|
<< ":/databases/2022-06-28-energylogs-micha.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(0,0,0)) // simulationStart (UTC)
|
|
<< ChargerPlugEvents( { ChargerPlugEvent(EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(6,0,0)), true) }) // pluggedInTime (UTC)
|
|
<< 24 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 20.0 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 0 // detailsStepStop
|
|
<< DetailsStepList() // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< false // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(22,0,0)) // targetDateTime
|
|
<< "ChargingModeEcoWithTargetTime" // chargingMode
|
|
<< 50 // carBatteryLevel
|
|
<< 0 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 1 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< false // energyStorageAvailable
|
|
<< 0 // energyStorageCapacity
|
|
<< 0.0 // energyStorageMaxChargingPower
|
|
<< 0.0 // energyStorageMaxDischargingPower
|
|
<< 50.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< false // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 16 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
0, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 50)
|
|
}
|
|
},
|
|
{
|
|
452, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 50)
|
|
}
|
|
},
|
|
{
|
|
467, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 9),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 51)
|
|
}
|
|
},
|
|
{
|
|
750, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
830, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
841, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
1000, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
1300, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
1440, { // 22:00
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 100)
|
|
}
|
|
}
|
|
} );
|
|
|
|
if (run2PhaseSimulations)
|
|
QTest::newRow("Kostal")
|
|
/* Simulation info */
|
|
<< "simulation-kostal-2-phase-16A" // simulationName
|
|
<< "Simulation (2 phase, charger 16A max, target 22:00 100%)" // simulationTitle
|
|
<< ":/databases/2022-08-12-kostal-energylogs.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 8, 14), QTime(0,0,0)) // simulationStart (UTC)
|
|
<< ChargerPlugEvents( { ChargerPlugEvent(EnergyTestBase::utcDateTime(QDate(2022, 8, 14), QTime(8,0,0)), true) }) // pluggedInTime (UTC)
|
|
<< 24 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 1.0 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 0 // detailsStepStop
|
|
<< DetailsStepList() // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< false // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 8, 14), QTime(22,0,0)) // targetDateTime
|
|
<< "ChargingModeEcoWithTargetTime" // chargingMode
|
|
<< 40 // carBatteryLevel
|
|
<< 0 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 2 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< false // energyStorageAvailable
|
|
<< 0 // energyStorageCapacity
|
|
<< 0.0 // energyStorageMaxChargingPower
|
|
<< 0.0 // energyStorageMaxDischargingPower
|
|
<< 50.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< false // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 16 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
0, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 40)
|
|
}
|
|
},
|
|
{
|
|
550, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
600, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 9),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 48)
|
|
}
|
|
},
|
|
{
|
|
820, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
823, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
847, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 80)
|
|
}
|
|
},
|
|
{
|
|
1050, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 100)
|
|
}
|
|
}
|
|
} );
|
|
|
|
if (run2PhaseSimulations)
|
|
QTest::newRow("Kostal")
|
|
/* Simulation info */
|
|
<< "simulation-kostal-2-phase-16A-away-2-hours" // simulationName
|
|
<< "Simulation (2 phase, charger 16A max, target 22:00 100%)" // simulationTitle
|
|
<< ":/databases/2022-08-12-kostal-energylogs.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 8, 14), QTime(0,0,0)) // simulationStart (UTC)
|
|
|
|
<< ChargerPlugEvents( {
|
|
ChargerPlugEvent(EnergyTestBase::utcDateTime(QDate(2022, 8, 14), QTime(12,0,0)), false),
|
|
ChargerPlugEvent(EnergyTestBase::utcDateTime(QDate(2022, 8, 14), QTime(14,00,0)), true, 10)
|
|
}) // pluggedInTime (UTC)
|
|
<< 24 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 1.0 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 0 // detailsStepStop
|
|
<< DetailsStepList() // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< false // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 8, 14), QTime(22,0,0)) // targetDateTime
|
|
<< "ChargingModeEcoWithTargetTime" // chargingMode
|
|
<< 40 // carBatteryLevel
|
|
<< 0 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 2 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< false // energyStorageAvailable
|
|
<< 0 // energyStorageCapacity
|
|
<< 0.0 // energyStorageMaxChargingPower
|
|
<< 0.0 // energyStorageMaxDischargingPower
|
|
<< 50.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< false // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 16 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
0, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 40)
|
|
}
|
|
},
|
|
{
|
|
550, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
600, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 9),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 48)
|
|
}
|
|
},
|
|
{
|
|
1300, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
1440, { // 22:00
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 100)
|
|
}
|
|
}
|
|
} );
|
|
|
|
if (run2PhaseSimulations)
|
|
QTest::newRow("Default")
|
|
/* Simulation info */
|
|
<< "simulation-2-phase-16A" // simulationName
|
|
<< "Simulation (2 phase, charger 16A max, target 22:00 100%)" // simulationTitle
|
|
<< ":/databases/2022-06-28-energylogs-micha.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(6,0,0)) // simulationStart (UTC)
|
|
<< ChargerPlugEvents() // pluggedInTime (UTC)
|
|
<< 18 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 20.0 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 0 // detailsStepStop
|
|
<< DetailsStepList() // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< false // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(22,0,0)) // targetDateTime
|
|
<< "ChargingModeEcoWithTargetTime" // chargingMode
|
|
<< 40 // carBatteryLevel
|
|
<< 0 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 2 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< false // energyStorageAvailable
|
|
<< 0 // energyStorageCapacity
|
|
<< 0.0 // energyStorageMaxChargingPower
|
|
<< 0.0 // energyStorageMaxDischargingPower
|
|
<< 50.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< false // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 16 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
0, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 40)
|
|
}
|
|
},
|
|
{
|
|
850, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
900, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
960, { // 22:00
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 100)
|
|
}
|
|
}
|
|
} );
|
|
|
|
if (run2PhaseSimulations)
|
|
QTest::newRow("Default")
|
|
/* Simulation info */
|
|
<< "simulation-2-phase-32A" // simulationName
|
|
<< "Simulation (2 phase, charger 32A max, target 22:00 100%)" // simulationTitle
|
|
<< ":/databases/2022-06-28-energylogs-micha.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(6,0,0)) // simulationStart (UTC)
|
|
<< ChargerPlugEvents() // pluggedInTime (UTC)
|
|
<< 18 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 20.0 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 0 // detailsStepStop
|
|
<< DetailsStepList() // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< false // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(22,0,0)) // targetDateTime
|
|
<< "ChargingModeEcoWithTargetTime" // chargingMode
|
|
<< 40 // carBatteryLevel
|
|
<< 0 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 2 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< false // energyStorageAvailable
|
|
<< 0 // energyStorageCapacity
|
|
<< 0.0 // energyStorageMaxChargingPower
|
|
<< 0.0 // energyStorageMaxDischargingPower
|
|
<< 50.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< false // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 32 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
0, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 40)
|
|
}
|
|
},
|
|
{
|
|
100, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
300, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 9),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 61)
|
|
}
|
|
},
|
|
{
|
|
470, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
586, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
800, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
950, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 30),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 99)
|
|
}
|
|
},
|
|
{
|
|
960, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 100)
|
|
}
|
|
}
|
|
} );
|
|
|
|
if (run3PhaseSimulations)
|
|
QTest::newRow("Default")
|
|
/* Simulation info */
|
|
<< "simulation-3-phase-16A" // simulationName
|
|
<< "Simulation (3 phase, charger 16A max, target 22:00 100%)" // simulationTitle
|
|
<< ":/databases/2022-06-28-energylogs-micha.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(6,0,0)) // simulationStart (UTC)
|
|
<< ChargerPlugEvents() // pluggedInTime (UTC)
|
|
<< 18 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 40.0 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 0 // detailsStepStop
|
|
<< DetailsStepList({200, 300, 400, 500}) // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< false // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(22,0,0)) // targetDateTime
|
|
<< "ChargingModeEcoWithTargetTime" // chargingMode
|
|
<< 40 // carBatteryLevel
|
|
<< 0 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 3 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< false // energyStorageAvailable
|
|
<< 0 // energyStorageCapacity
|
|
<< 0.0 // energyStorageMaxChargingPower
|
|
<< 0.0 // energyStorageMaxDischargingPower
|
|
<< 50.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< false // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 16 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
0, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 40)
|
|
}
|
|
},
|
|
{
|
|
200, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 11),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 57)
|
|
}
|
|
},
|
|
{
|
|
300, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 13),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 83)
|
|
}
|
|
},
|
|
{
|
|
400, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 11),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 100)
|
|
}
|
|
},
|
|
{
|
|
700, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 100)
|
|
}
|
|
}
|
|
} );
|
|
|
|
|
|
if (run3PhaseSimulations)
|
|
QTest::newRow("Default")
|
|
/* Simulation info */
|
|
<< "simulation-3-phase-32A" // simulationName
|
|
<< "Simulation (3 phase, charger 32A max, target 22:00 100%)" // simulationTitle
|
|
<< ":/databases/2022-06-28-energylogs-micha.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(6,0,0)) // simulationStart (UTC)
|
|
<< ChargerPlugEvents() // pluggedInTime (UTC)
|
|
<< 18 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 20.0 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 0 // detailsStepStop
|
|
<< DetailsStepList({ 480, 500, 600, 950, 960 }) // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< false // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(22,0,0)) // targetDateTime
|
|
<< "ChargingModeEcoWithTargetTime" // chargingMode
|
|
<< 40 // carBatteryLevel
|
|
<< 0 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 3 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< false // energyStorageAvailable
|
|
<< 0 // energyStorageCapacity
|
|
<< 0.0 // energyStorageMaxChargingPower
|
|
<< 0.0 // energyStorageMaxDischargingPower
|
|
<< 50.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< false // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 32 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
100, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 40)
|
|
}
|
|
},
|
|
{
|
|
200, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
300, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
400, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true)
|
|
}
|
|
},
|
|
{
|
|
480, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
500, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 82)
|
|
}
|
|
},
|
|
{
|
|
600, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false)
|
|
}
|
|
},
|
|
{
|
|
950, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 98) // Finish 10 min early
|
|
}
|
|
},
|
|
{
|
|
960, { // 22:00
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 100)
|
|
}
|
|
}
|
|
} );
|
|
|
|
if (runPhaseSwitchingSimulations)
|
|
QTest::newRow("Default")
|
|
/* Simulation info */
|
|
<< "simulation-phase-switching-16A" // simulationName
|
|
<< "Simulation (phase switching, charger 16A max, surplus only)" // simulationTitle
|
|
<< ":/databases/2022-06-28-energylogs-micha.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(6,0,0)) // simulationStart (UTC)
|
|
<< ChargerPlugEvents() // pluggedInTime (UTC)
|
|
<< 18 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 45.0 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 0 // detailsStepStop
|
|
<< DetailsStepList({80, 150, 310, 400, 470}) // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< false // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(22,0,0)) // targetDateTime
|
|
<< "ChargingModeEco" // chargingMode
|
|
<< 40 // carBatteryLevel
|
|
<< 0 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 3 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< false // energyStorageAvailable
|
|
<< 0 // energyStorageCapacity
|
|
<< 0.0 // energyStorageMaxChargingPower
|
|
<< 0.0 // energyStorageMaxDischargingPower
|
|
<< 50.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< true // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 16 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
0, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 40)
|
|
}
|
|
},
|
|
{
|
|
80, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 40)
|
|
}
|
|
},
|
|
{
|
|
150, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 10),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 50)
|
|
}
|
|
},
|
|
{
|
|
310, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 16),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 91)
|
|
}
|
|
},
|
|
{
|
|
400, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 13),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 100)
|
|
}
|
|
},
|
|
{
|
|
470, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 9),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, true),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 100)
|
|
}
|
|
},
|
|
} );
|
|
|
|
if (runPhaseSwitchingSimulations)
|
|
QTest::newRow("Default")
|
|
/* Simulation info */
|
|
<< "simulation-energy-storage-phase-switching" // simulationName
|
|
<< "Simulation energy storage, phase switching" // simulationTitle
|
|
<< ":/databases/2022-06-28-energylogs-micha.sqlite" // databaseName
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(0,0,0)) // simulationStart (UTC)
|
|
<< ChargerPlugEvents() // pluggedInTime (UTC)
|
|
<< 36 // simulationHours
|
|
<< EnergyLogs::SampleRate1Min
|
|
<< 45.0 // productionScaling
|
|
<< 0 // detailsStepStart
|
|
<< 10 // detailsStepStop
|
|
<< DetailsStepList({}) // detailsStepList
|
|
|
|
/* Houshold info */
|
|
<< 32 // phase limit (A)
|
|
<< false // spotMarketEnabled
|
|
<< ":/resources/dataset-1.json" // spotMarketResourceData
|
|
<< 0.5 // acquisitionTolerance
|
|
<< 0.9 // batteryLevelConsideration
|
|
|
|
/* Charging Info */
|
|
<< 100.0 // targetPercentage
|
|
<< EnergyTestBase::utcDateTime(QDate(2022, 6, 27), QTime(22,0,0)) // targetDateTime
|
|
<< "ChargingModeEco" // chargingMode
|
|
<< 40 // carBatteryLevel
|
|
<< 0 // dailySpotMarketPercentage
|
|
|
|
/* Car settings */
|
|
<< 50 // carCapacity
|
|
<< 6 // carMinChargingCurrent
|
|
<< 3 // carPhaseCount
|
|
|
|
/* Energy storage */
|
|
<< true // energyStorageAvailable
|
|
<< 12 // energyStorageCapacity
|
|
<< 5000.0 // energyStorageMaxChargingPower
|
|
<< 5000.0 // energyStorageMaxDischargingPower
|
|
<< 10.0 // energyStorageInitialBatteyLevel
|
|
|
|
<< true // chargerConnected
|
|
<< false // chargerPower
|
|
<< "ABC" // chargerPhases
|
|
<< true // canSwitchPhaseCount
|
|
<< 6 // chargerMaxChargingCurrent
|
|
<< 16 //chargerMaxChargingCurrentMaxValue
|
|
|
|
<< SimulationIterationTest ( {
|
|
{
|
|
0, {
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeMaxChargingCurrent, 6),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeCharging, false),
|
|
SimulationTestPoint(SimulationTestPoint::TestTypeStateOfCharge, 40)
|
|
}
|
|
}
|
|
} );
|
|
}
|
|
|
|
void Simulation::run()
|
|
{
|
|
QFETCH(QString, simulationName);
|
|
QFETCH(QString, simulationTitle);
|
|
QFETCH(QString, databaseName);
|
|
QFETCH(QDateTime, simulationStart);
|
|
QFETCH(ChargerPlugEvents, plugEvents);
|
|
QFETCH(int, simulationHours);
|
|
QFETCH(EnergyLogs::SampleRate, sampleRate);
|
|
QFETCH(double, productionScaling);
|
|
QFETCH(int, detailsStepStart);
|
|
QFETCH(int, detailsStepStop);
|
|
QFETCH(DetailsStepList, detailsStepList);
|
|
|
|
QFETCH(int, phasePowerLimit);
|
|
QFETCH(bool, spotMarketEnabled);
|
|
QFETCH(QString, spotMarketResourceData);
|
|
QFETCH(double, acquisitionTolerance);
|
|
QFETCH(double, batteryLevelConsideration);
|
|
|
|
QFETCH(double, targetPercentage);
|
|
QFETCH(QDateTime, targetDateTime);
|
|
QFETCH(QString, chargingMode);
|
|
QFETCH(int, carBatteryLevel);
|
|
QFETCH(int, dailySpotMarketPercentage);
|
|
|
|
QFETCH(int, carCapacity);
|
|
QFETCH(int, carMinChargingCurrent);
|
|
QFETCH(int, carPhaseCount);
|
|
|
|
QFETCH(bool, energyStorageAvailable);
|
|
QFETCH(int, energyStorageCapacity);
|
|
QFETCH(double, energyStorageMaxChargingPower);
|
|
QFETCH(double, energyStorageMaxDischargingPower);
|
|
QFETCH(double, energyStorageInitialBatteyLevel);
|
|
|
|
QFETCH(bool, chargerConnected);
|
|
QFETCH(bool, chargerPower);
|
|
QFETCH(QString, chargerPhases);
|
|
QFETCH(bool, canSwitchPhaseCount);
|
|
QFETCH(int, chargerMaxChargingCurrent);
|
|
QFETCH(int, chargerMaxChargingCurrentMaxValue);
|
|
|
|
QFETCH(SimulationIterationTest, iterationTest);
|
|
|
|
|
|
QStringList loggingDefaultList = {
|
|
"*.debug=false",
|
|
"Application.debug=true",
|
|
"LogEngine.info=false",
|
|
"Simulation.debug=true",
|
|
"Experiences.debug=false",
|
|
"NymeaEnergy.debug=false",
|
|
"EnergyMocks.debug=false",
|
|
"DBus.warning=false",
|
|
};
|
|
QString loggingRulesDefault = loggingDefaultList.join("\n");
|
|
|
|
QStringList loggingDetailsList = {
|
|
"*.debug=false",
|
|
"Application.debug=true",
|
|
"LogEngine.info=false",
|
|
"Simulation.debug=true",
|
|
"Experiences.debug=false",
|
|
"NymeaEnergy.debug=true",
|
|
"EnergyMocks.debug=false",
|
|
"DBus.warning=false",
|
|
};
|
|
QString loggingRulesDetails = loggingDetailsList.join("\n");
|
|
|
|
QStringList availableChargingModes;
|
|
availableChargingModes << "ChargingModeNormal";
|
|
availableChargingModes << "ChargingModeEco";
|
|
availableChargingModes << "ChargingModeEcoWithTargetTime";
|
|
QVERIFY2(availableChargingModes.contains(chargingMode), "Unknown charging mode passed to the simulation. Please compair the list with the ChargingMode enum.");
|
|
|
|
if (canSwitchPhaseCount)
|
|
QVERIFY2(chargerPhases == "ABC", "If the charger supports phase count switching all 3 phases must be connected.");
|
|
|
|
cleanupTestCase();
|
|
m_energyLogDbFilePath = databaseName;
|
|
initTestCase(loggingRulesDefault);
|
|
|
|
// Print simulation init details
|
|
QLoggingCategory::setFilterRules(loggingRulesDefault);
|
|
|
|
QVariant response; QVariantMap params;
|
|
QNetworkReply *reply = nullptr;
|
|
QSignalSpy packetSpy(m_mockTcpServer, &MockTcpServer::outgoingData);;
|
|
|
|
Electricity::Phases chargerPhasesConverted = Electricity::convertPhasesFromString(chargerPhases);
|
|
|
|
// Set phase power limit
|
|
response = injectAndWait("NymeaEnergy.SetPhasePowerLimit", QVariantMap({{"phasePowerLimit", phasePowerLimit}}));
|
|
QVERIFY(response.toMap().value("params").toMap().value("energyError").toString() == "EnergyErrorNoError");
|
|
|
|
// Add mock spotmarket provider
|
|
SpotMarketManager *spotMarketManager = m_experiencePlugin->spotMarketManager();
|
|
SpotMarketDataProviderMock *mockProvider = new SpotMarketDataProviderMock(nullptr, this);
|
|
QVERIFY(mockProvider->prepareResourceData(spotMarketResourceData, simulationStart.toUTC()));
|
|
QVERIFY(spotMarketManager->registerProvider(mockProvider));
|
|
QVERIFY(spotMarketManager->changeProvider(mockProvider->providerId()));
|
|
|
|
// Enabke/disable spot market
|
|
response = injectAndWait("NymeaEnergy.SetSpotMarketConfiguration", QVariantMap({ {"enabled", spotMarketEnabled }, {"providerId", mockProvider->providerId()} }));
|
|
QCOMPARE(response.toMap().value("params").toMap().value("energyError").toString(), "EnergyErrorNoError");
|
|
QCOMPARE(m_experiencePlugin->spotMarketManager()->enabled(), spotMarketEnabled);
|
|
|
|
// Set initial acquisition tolerance
|
|
params.clear(); response.clear();
|
|
params.insert("acquisitionTolerance", acquisitionTolerance);
|
|
response = injectAndWait("NymeaEnergy.SetAcquisitionTolerance", params);
|
|
verifyEnergyError(response);
|
|
|
|
// Set battery level consideration
|
|
params.clear(); response.clear();
|
|
params.insert("batteryLevelConsideration", batteryLevelConsideration);
|
|
response = injectAndWait("NymeaEnergy.SetBatteryLevelConsideration", params);
|
|
verifyEnergyError(response);
|
|
|
|
// Add mock meter
|
|
QUuid meterThingId = addMeter();
|
|
QVERIFY2(!meterThingId.isNull(), "Did not receive valid ThingId");
|
|
if (packetSpy.count() == 0) packetSpy.wait();
|
|
checkNotification(packetSpy, "Integrations.ThingAdded");
|
|
packetSpy.clear();
|
|
|
|
// Set it as root meter
|
|
m_experiencePlugin->energyManager()->setRootMeter(meterThingId);
|
|
|
|
// Make sure this is our root meter now
|
|
response = injectAndWait("Energy.GetRootMeter");
|
|
QCOMPARE(response.toMap().value("params").toMap().value("rootMeterThingId").toUuid(), meterThingId);
|
|
packetSpy.clear();
|
|
|
|
// Add the charger
|
|
QUuid evChargerId;
|
|
if (canSwitchPhaseCount) {
|
|
evChargerId = addChargerWithPhaseCountSwitching(chargerPhases, chargerMaxChargingCurrentMaxValue);
|
|
} else {
|
|
evChargerId = addCharger(chargerPhases, chargerMaxChargingCurrentMaxValue);
|
|
}
|
|
|
|
QVERIFY2(!evChargerId.isNull(), "Did not receive valid ThingId");
|
|
if (packetSpy.count() == 0) packetSpy.wait();
|
|
checkNotification(packetSpy, "Integrations.ThingAdded");
|
|
|
|
// Add the car
|
|
QUuid carThingId = addCar();
|
|
QVERIFY2(!carThingId.isNull(), "Did not receive valid ThingId");
|
|
if (packetSpy.count() == 0) packetSpy.wait();
|
|
checkNotification(packetSpy, "Integrations.ThingAdded");
|
|
|
|
// Add energy storage if available
|
|
QUuid energyStorageThingId;
|
|
if (energyStorageAvailable) {
|
|
energyStorageThingId = addEnergyStorage(energyStorageCapacity, energyStorageMaxChargingPower, energyStorageMaxDischargingPower);
|
|
QVERIFY2(!energyStorageThingId.isNull(), "Did not receive valid ThingId");
|
|
if (packetSpy.count() == 0) packetSpy.wait();
|
|
checkNotification(packetSpy, "Integrations.ThingAdded");
|
|
}
|
|
|
|
// ==============================================================================
|
|
// Set states of car and charger
|
|
|
|
Thing *carThing = NymeaCore::instance()->thingManager()->findConfiguredThing(carThingId);
|
|
QVERIFY2(carThing != nullptr, "Failed to find car thing");
|
|
carThing->setSettingValue(carThing->thingClass().settingsTypes().findByName("phaseCount").id(), carPhaseCount);
|
|
carThing->setSettingValue(carThing->thingClass().settingsTypes().findByName("capacity").id(), carCapacity);
|
|
carThing->setSettingValue(carThing->thingClass().settingsTypes().findByName("minChargingCurrent").id(), carMinChargingCurrent);
|
|
carThing->setStateValue("batteryLevel", carBatteryLevel);
|
|
|
|
Thing *chargerThing = NymeaCore::instance()->thingManager()->findConfiguredThing(evChargerId);
|
|
QVERIFY2(chargerThing != nullptr, "Failed to find charger thing");
|
|
chargerThing->setStateValue("connected", chargerConnected);
|
|
chargerThing->setStateValue("power", chargerPower);
|
|
chargerThing->setStateValue("maxChargingCurrent", chargerMaxChargingCurrent);
|
|
chargerThing->setStateValue("maxChargingCurrentMaxValue", chargerMaxChargingCurrentMaxValue);
|
|
chargerThing->setStateValue("pluggedIn", true); // Initially always plugged in, the rest can be handeld using the plug events
|
|
|
|
// This will update all internal states not set directly
|
|
updateChargerMeter(chargerThing);
|
|
|
|
Thing *meterThing = NymeaCore::instance()->thingManager()->findConfiguredThing(meterThingId);
|
|
QVERIFY2(meterThing != nullptr, "Failed to find meter thing");
|
|
meterThing->setStateValue("connected", true);
|
|
|
|
// Energy storage states
|
|
Thing *energyStorageThing = nullptr;
|
|
if (energyStorageAvailable) {
|
|
energyStorageThing = NymeaCore::instance()->thingManager()->findConfiguredThing(energyStorageThingId);
|
|
energyStorageThing->setStateValue("currentPower", 0);
|
|
energyStorageThing->setStateValue("batteryLevel", energyStorageInitialBatteyLevel);
|
|
energyStorageThing->setProperty("preciseBatteryLevel", energyStorageInitialBatteyLevel * 1.0); // For precise runtime calculations
|
|
printStates(energyStorageThing);
|
|
}
|
|
|
|
// printStates(chargerThing);
|
|
// printStates(carThing);
|
|
// printStates(meterThing);
|
|
|
|
// Set charging info with our charger and car, this should trigger the evaluation
|
|
QVariantMap chargingInfoMap;
|
|
chargingInfoMap.insert("evChargerId", evChargerId);
|
|
chargingInfoMap.insert("assignedCarId", carThingId);
|
|
chargingInfoMap.insert("chargingMode", chargingMode);
|
|
chargingInfoMap.insert("endDateTime", targetDateTime.toMSecsSinceEpoch() / 1000);
|
|
chargingInfoMap.insert("targetPercentage", targetPercentage);
|
|
chargingInfoMap.insert("spotMarketChargingEnabled", spotMarketEnabled);
|
|
chargingInfoMap.insert("dailySpotMarketPercentage", dailySpotMarketPercentage);
|
|
response = injectAndWait("NymeaEnergy.SetChargingInfo", QVariantMap({{"chargingInfo", chargingInfoMap}}));
|
|
QCOMPARE(response.toMap().value("status").toString(), QString("success"));
|
|
QCOMPARE(response.toMap().value("params").toMap().value("energyError").toString(), QString("EnergyErrorNoError"));
|
|
|
|
uint effectivePhaseCount;
|
|
if (canSwitchPhaseCount) {
|
|
effectivePhaseCount = chargerThing->stateValue("phaseCount").toUInt();
|
|
} else {
|
|
effectivePhaseCount = qMin((uint)carPhaseCount, Electricity::getPhaseCount(chargerPhasesConverted));
|
|
}
|
|
|
|
QString usedPhases;
|
|
if (effectivePhaseCount >= 1)
|
|
usedPhases.append("A");
|
|
|
|
if (effectivePhaseCount >= 2)
|
|
usedPhases.append("B");
|
|
|
|
if (effectivePhaseCount >= 3)
|
|
usedPhases.append("C");
|
|
|
|
chargerThing->setStateValue("usedPhases", usedPhases);
|
|
|
|
|
|
// Note: we want to have the limit negative, so we see better where the limit is and why the chaging stopped
|
|
double aquisitionToleranceLimit = -(effectivePhaseCount * carMinChargingCurrent * 230.0 * acquisitionTolerance);
|
|
|
|
// Simulation output
|
|
QDir simulationBaseDir = QDir(QDir::currentPath() + QDir::separator() + "simulations");
|
|
|
|
QDir workspaceDir = QDir(simulationBaseDir.absolutePath() + QDir::separator() + "workspace");
|
|
if (!workspaceDir.exists()) {
|
|
//QVERIFY2(outputDir.removeRecursively(), "Failed to cleanup output dir");
|
|
QVERIFY2(workspaceDir.mkpath(workspaceDir.path()), "Failed to create results dir");
|
|
}
|
|
|
|
QDir outputDir = QDir(workspaceDir.absolutePath() + QDir::separator() + simulationName);
|
|
if (!outputDir.exists()) {
|
|
// QVERIFY2(outputDir.removeRecursively(), "Failed to cleanup output dir");
|
|
QVERIFY2(outputDir.mkpath(outputDir.path()), "Failed to create output dir");
|
|
}
|
|
|
|
QDir resultsDir = QDir(simulationBaseDir.absolutePath() + QDir::separator() + "results");
|
|
if (!resultsDir.exists()) {
|
|
//QVERIFY2(outputDir.removeRecursively(), "Failed to cleanup output dir");
|
|
QVERIFY2(resultsDir.mkpath(resultsDir.path()), "Failed to create results dir");
|
|
}
|
|
|
|
QFile gnuplotLogFile(outputDir.path() + QDir::separator() + "simulation.csv");
|
|
QVERIFY2(gnuplotLogFile.open(QIODevice::ReadWrite | QIODevice::Truncate), QString("Failed to open logfile for gnuplot" + gnuplotLogFile.fileName() + ": " + gnuplotLogFile.errorString()).toUtf8());
|
|
QTextStream gnuplotLogFileStream(&gnuplotLogFile);
|
|
|
|
QFile gnuplotOriginalLogFile(outputDir.path() + QDir::separator() + "original.csv");
|
|
QVERIFY2(gnuplotOriginalLogFile.open(QIODevice::ReadWrite | QIODevice::Truncate), "Failed to open logfile for gnuplot");
|
|
QTextStream gnuplotOriginalLogFileStream(&gnuplotOriginalLogFile);
|
|
|
|
|
|
// ==============================================================================
|
|
// All set up, lets start simulating
|
|
|
|
QDateTime simulationEnd = simulationStart.addSecs(simulationHours * 3600);
|
|
|
|
PowerBalanceLogEntries powerBalanceLogs = m_experiencePlugin->energyManager()->logs()->powerBalanceLogs(sampleRate, simulationStart, simulationEnd);
|
|
qCDebug(dcSimulation()) << "Simulation start" << simulationStart;
|
|
qCDebug(dcSimulation()) << "Simulation end" << simulationEnd;
|
|
qCDebug(dcSimulation()) << "Loaded" << powerBalanceLogs.count() << "log entries for that day";
|
|
|
|
// Simulation helpers
|
|
int simulationProgress = 0;
|
|
|
|
// Disable init details
|
|
QLoggingCategory::setFilterRules(loggingRulesDefault);
|
|
|
|
// Run the simulation
|
|
for (int i = 0; i < powerBalanceLogs.count(); i++) {
|
|
|
|
bool debugEnabled = (i >= detailsStepStart && i <= detailsStepStop) || detailsStepList.contains(i);
|
|
const PowerBalanceLogEntry entry = powerBalanceLogs.at(i);
|
|
QDateTime currentDateTime = entry.timestamp().toUTC();
|
|
|
|
// Calculate progress
|
|
if (debugEnabled) {
|
|
qCDebug(dcSimulation()) << "###############################################################################################################";
|
|
qCDebug(dcSimulation()) << "Step" << i << ":" << currentDateTime.toUTC().toString("yyyy.MM.dd hh:mm");
|
|
}
|
|
|
|
effectivePhaseCount = chargerThing->stateValue("phaseCount").toUInt();
|
|
usedPhases = chargerThing->stateValue("usedPhases").toString();
|
|
|
|
// Update mocked spotmarket data provider
|
|
mockProvider->setCurrentDataTime(currentDateTime.toUTC());
|
|
|
|
// Print simulation progress
|
|
double simulationProgressPrecise = i * 100 / powerBalanceLogs.count();
|
|
if (simulationProgress != qRound(simulationProgressPrecise)) {
|
|
simulationProgress = qRound(simulationProgressPrecise);
|
|
if (simulationProgress % 10 == 0) {
|
|
qCDebug(dcSimulation()) << simulationName << currentDateTime.toUTC().toString("hh:mm") << simulationProgress << "% (" << i << ")";
|
|
}
|
|
}
|
|
|
|
// Enable logs in the interesting simulation steps
|
|
if (debugEnabled) {
|
|
QLoggingCategory::setFilterRules(loggingRulesDetails);
|
|
} else {
|
|
QLoggingCategory::setFilterRules(loggingRulesDefault);
|
|
}
|
|
|
|
// Get the current situation befor running the simulation step
|
|
double totalProduction = entry.production() * productionScaling;
|
|
double totalProductionDifference = totalProduction - entry.production();
|
|
double scaledCurrentPower = entry.acquisition() + totalProductionDifference;
|
|
//qCDebug(dcSimulation()) << "Scale production using" << productionScaling << entry.production() << "-->" << totalProduction << totalProductionDifference;
|
|
//qCDebug(dcSimulation()) << "Scale aquisition using" << entry.acquisition() << "-->" << scaledCurrentPower;
|
|
|
|
// Distribute the load before battery and charger on 3 phases
|
|
double phaseLoad = scaledCurrentPower / 3;
|
|
|
|
// -------------------- Charger
|
|
|
|
// Handle plug events
|
|
foreach(const ChargerPlugEvent &plugEvent, plugEvents) {
|
|
if (plugEvent.dateTime.date() == currentDateTime.toUTC().date() &&
|
|
plugEvent.dateTime.time().hour() == currentDateTime.toUTC().time().hour() &&
|
|
plugEvent.dateTime.time().minute() == currentDateTime.toUTC().time().minute()) {
|
|
|
|
// Plug event
|
|
chargerThing->setStateValue("pluggedIn", plugEvent.pluggedIn);
|
|
if (plugEvent.percentageUsed != 0) {
|
|
double batteryLevel = carThing->stateValue("batteryLevel").toDouble();
|
|
batteryLevel -= plugEvent.percentageUsed;
|
|
if (batteryLevel < 0) {
|
|
batteryLevel = 0;
|
|
}
|
|
qCDebug(dcSimulation()) << "-->" << currentDateTime.toUTC().toString("hh:mm") << "New car battery level" << batteryLevel << "(old:" << carThing->stateValue("batteryLevel").toDouble() << ")";
|
|
carThing->setStateValue("batteryLevel", batteryLevel);
|
|
}
|
|
qCDebug(dcSimulation()) << "-->" << currentDateTime.toUTC().toString("hh:mm") << "Car has been" << (plugEvent.pluggedIn ? "plugged in" : "unplugged");
|
|
}
|
|
}
|
|
|
|
// Let the charger set all power, voltage etc....
|
|
updateChargerMeter(chargerThing);
|
|
double chargerCurrentPower = chargerThing->stateValue("currentPower").toDouble();
|
|
|
|
double totalConsumption = chargerCurrentPower + entry.consumption();
|
|
|
|
// Totals before battery
|
|
double totalCurrentPower = totalConsumption + totalProduction;
|
|
|
|
// All producers and all consumers have been summed up, charge / discharge the battery and create a final total balance
|
|
|
|
// -------------------- Energy storage
|
|
|
|
double energyStorageCurrentPower = 0;
|
|
uint energyStorageBatteryLevel = 0;
|
|
|
|
// All consumers should have what they get, put the rest into or from the storage within limits
|
|
|
|
if (energyStorageAvailable) {
|
|
|
|
// Calculate the new battery level depending on the previouse step.
|
|
|
|
double esCurrentPower = energyStorageThing->stateValue("currentPower").toDouble();
|
|
double esBatteryLevel = energyStorageThing->property("preciseBatteryLevel").toDouble();
|
|
double esCapacity = energyStorageThing->stateValue("capacity").toDouble();
|
|
|
|
// Let's caclulate the new percentage depending on the rate of the last minute...
|
|
|
|
// We charged/discharged the last minute with energyStorageCurrentPower W
|
|
double energyChargedDischargedkWh = esCurrentPower * 60 / 60 / 60 / 1000;
|
|
double addedPercentage = energyChargedDischargedkWh * 100.0 / esCapacity;
|
|
double newBatteryLevel = esBatteryLevel += addedPercentage;
|
|
|
|
if (totalCurrentPower < 0 && newBatteryLevel < 100) {
|
|
energyStorageCurrentPower = qMin(energyStorageMaxChargingPower, -totalCurrentPower);
|
|
energyStorageBatteryLevel = newBatteryLevel;
|
|
energyStorageThing->setProperty("preciseBatteryLevel", newBatteryLevel);
|
|
setEnergyStorageStates(energyStorageBatteryLevel, energyStorageCurrentPower);
|
|
} else if (totalCurrentPower > 0 && newBatteryLevel > 0) {
|
|
energyStorageCurrentPower = - qMin(energyStorageMaxDischargingPower, totalCurrentPower);
|
|
energyStorageBatteryLevel = newBatteryLevel;
|
|
energyStorageThing->setProperty("preciseBatteryLevel", newBatteryLevel);
|
|
setEnergyStorageStates(energyStorageBatteryLevel, energyStorageCurrentPower);
|
|
} else {
|
|
energyStorageBatteryLevel = newBatteryLevel;
|
|
energyStorageThing->setProperty("preciseBatteryLevel", newBatteryLevel);
|
|
setEnergyStorageStates(energyStorageBatteryLevel, energyStorageCurrentPower);
|
|
}
|
|
|
|
//qCDebug(dcSimulation()) << "Energy storage charged with" << energyStorageCurrentPower << "W" << addedPercentage << "% added to total" << energyStorageBatteryLevel << "%";
|
|
}
|
|
|
|
// -------------------- Meter
|
|
|
|
totalCurrentPower += energyStorageCurrentPower;
|
|
phaseLoad += energyStorageCurrentPower / 3;
|
|
|
|
// Add the charger power in the aproperiate phase
|
|
QVariantMap phases = QVariantMap({ {"A", phaseLoad + chargerThing->stateValue("currentPowerPhaseA").toDouble()},
|
|
{"B", phaseLoad + chargerThing->stateValue("currentPowerPhaseB").toDouble()},
|
|
{"C", phaseLoad + chargerThing->stateValue("currentPowerPhaseC").toDouble()} });
|
|
|
|
reply = setMeterStates(phases, true);
|
|
QSignalSpy setMeterStatesReplySpy(reply, &QNetworkReply::finished);
|
|
if (setMeterStatesReplySpy.count() == 0) setMeterStatesReplySpy.wait();
|
|
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
|
|
|
// -------------------- Run charging manager update
|
|
|
|
// Set charger information and pass them to the logic
|
|
ThingPowerLogEntry chargerPowerEntry(currentDateTime.toUTC(), chargerThing->id(), chargerThing->stateValue("currentPower").toDouble(), 0, 0);
|
|
m_experiencePlugin->smartChargingManager()->simulationCallUpdateManualSoCsWithMeter(sampleRate, chargerPowerEntry);
|
|
|
|
// Update smart charging manager with the current root meter and charger situation
|
|
m_experiencePlugin->smartChargingManager()->simulationCallUpdate(currentDateTime.toUTC());
|
|
|
|
// Fetch information after simulation iteration
|
|
double carBatteryPercentage = carThing->stateValue("batteryLevel").toDouble();
|
|
int maxChargingCurrent = chargerThing->stateValue("maxChargingCurrent").toInt();
|
|
chargerPower = chargerThing->stateValue("power").toBool();
|
|
chargerCurrentPower = chargerThing->stateValue("currentPower").toDouble();
|
|
|
|
|
|
if (debugEnabled | iterationTest.contains(i)) {
|
|
qCDebug(dcSimulation()) << "Step" << i;
|
|
qCDebug(dcSimulation()) << "- Total power:" << totalCurrentPower << "Production:" << totalProduction << "Consumption:" << totalConsumption;
|
|
if (energyStorageAvailable) {
|
|
qCDebug(dcSimulation()) << "- Energy storage:" << energyStorageCurrentPower << energyStorageThing->property("preciseBatteryLevel").toDouble() << "%";
|
|
}
|
|
qCDebug(dcSimulation()) << "- Meter phases: A:" << meterThing->stateValue("currentPowerPhaseA").toDouble() << "W | B:"
|
|
<< meterThing->stateValue("currentPowerPhaseB").toDouble() << "W | C:" << meterThing->stateValue("currentPowerPhaseC").toDouble() << "W";
|
|
qCDebug(dcSimulation()) << "- Charger:" << chargerCurrentPower << "[W] (" << maxChargingCurrent << "[A]" << (chargerCurrentPower ? "On)" : "Off )") << effectivePhaseCount << usedPhases;
|
|
qCDebug(dcSimulation()) << "- Charger phases: A:" << chargerThing->stateValue("currentPowerPhaseA").toDouble() << "W | B:"
|
|
<< chargerThing->stateValue("currentPowerPhaseB").toDouble() << "W | C:" << chargerThing->stateValue("currentPowerPhaseC").toDouble() << "W";
|
|
qCDebug(dcSimulation()) << "- Car battery:" << carBatteryPercentage;
|
|
qCDebug(dcSimulation()) << "--------------------------------";
|
|
|
|
// printStates(meterThing);
|
|
// printStates(chargerThing);
|
|
// printStates(carThing);
|
|
|
|
}
|
|
|
|
// Verify test points
|
|
foreach(const SimulationTestPoint &testPoint, iterationTest.value(i)) {
|
|
switch(testPoint.testType()) {
|
|
case SimulationTestPoint::TestTypeCharging:
|
|
QVERIFY2(chargerPower == testPoint.expectedValue().toBool(),
|
|
qPrintable(QString("Simulation: %1 - %2 Step: %3 expected \"%4\" from the testpoint but is actually \"%5\"")
|
|
.arg(simulationName)
|
|
.arg(simulationTitle)
|
|
.arg(i)
|
|
.arg(testPoint.expectedValue().toBool() ? "true" : "false")
|
|
.arg(chargerPower ? "true" : "false")));
|
|
|
|
break;
|
|
case SimulationTestPoint::TestTypeMaxChargingCurrent:
|
|
QVERIFY2(maxChargingCurrent == testPoint.expectedValue().toInt(),
|
|
qPrintable(QString("Simulation: %1 - %2 Step: %3 expected \"%4\" from the testpoint but is actually \"%5\"")
|
|
.arg(simulationName)
|
|
.arg(simulationTitle)
|
|
.arg(i)
|
|
.arg(testPoint.expectedValue().toInt())
|
|
.arg(maxChargingCurrent)));
|
|
|
|
break;
|
|
case SimulationTestPoint::TestTypeStateOfCharge:
|
|
QVERIFY2(qFuzzyCompare(carBatteryPercentage, testPoint.expectedValue().toDouble()),
|
|
qPrintable(QString("Simulation: %1 - %2 Step: %3 expected \"%4\" from the testpoint but is actually \"%5\"")
|
|
.arg(simulationName)
|
|
.arg(simulationTitle)
|
|
.arg(i)
|
|
.arg(testPoint.expectedValue().toDouble())
|
|
.arg(carBatteryPercentage)));
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
// -------------------- Data logging
|
|
|
|
// Log the simulation data
|
|
gnuplotLogFileStream << currentDateTime.toMSecsSinceEpoch() / 1000 << ", " << // 1
|
|
totalCurrentPower << ", " << // 2
|
|
totalProduction << ", " << // 3
|
|
totalConsumption << ", " << // 4
|
|
chargerCurrentPower << ", " << // 5
|
|
maxChargingCurrent << ", " << // 6
|
|
(chargerPower ? "1" : "0") << ", " << // 7
|
|
chargerThing->state("maxChargingCurrent").minValue().toDouble() * 230 * effectivePhaseCount << ", " << // 8
|
|
chargerThing->state("maxChargingCurrent").maxValue().toDouble() * 230 * effectivePhaseCount << ", " << // 9
|
|
phasePowerLimit * 230 * effectivePhaseCount << ", " << // 10
|
|
carBatteryPercentage << ", " << // 11
|
|
i << ", " << // 12
|
|
aquisitionToleranceLimit << ", " << // 13
|
|
(chargerThing->stateValue("pluggedIn").toBool() ? 10 : 0 ) << ", "; // 14
|
|
if (spotMarketEnabled) {
|
|
const ScoreEntries weightedEntries = spotMarketManager->weightedScoreEntries(currentDateTime.date());
|
|
const ScoreEntry currentScore = weightedEntries.getScoreEntry(currentDateTime.toUTC());
|
|
QVERIFY(!currentScore.isNull());
|
|
gnuplotLogFileStream << currentScore.weighting() * 100 << ", "; // 15
|
|
gnuplotLogFileStream << currentScore.value() / 10.0 << ", "; // 16 Price
|
|
} else {
|
|
gnuplotLogFileStream << 0 << ", "; // 15
|
|
gnuplotLogFileStream << 0 << ", "; // 16
|
|
}
|
|
if (energyStorageAvailable) {
|
|
gnuplotLogFileStream << energyStorageCurrentPower << ", "; // 17
|
|
gnuplotLogFileStream << energyStorageBatteryLevel << ", "; // 18
|
|
} else {
|
|
gnuplotLogFileStream << 0 << ", "; // 17
|
|
gnuplotLogFileStream << 0 << ", "; // 18
|
|
}
|
|
gnuplotLogFileStream << "\n";
|
|
|
|
|
|
|
|
// Log Unchanged for raw data analysis
|
|
gnuplotOriginalLogFileStream << currentDateTime.toMSecsSinceEpoch() / 1000 << ", " << // 1
|
|
scaledCurrentPower << ", " << // 2
|
|
totalProduction << ", " << // 3
|
|
entry.consumption() << ", " << // 4
|
|
phasePowerLimit * 230 * effectivePhaseCount << ", " << // 5
|
|
i << ", " << // 6
|
|
"\n";
|
|
}
|
|
|
|
gnuplotLogFile.close();
|
|
gnuplotOriginalLogFile.close();
|
|
|
|
// Draw original data
|
|
QStringList scriptLines;
|
|
QStringList plotLines;
|
|
|
|
// Plot with: 1h = 200 px
|
|
int height = 800;
|
|
int width = simulationHours * 200;
|
|
|
|
QString originalImageName = simulationName + "-00-original.png";
|
|
QString simulationImageName = simulationName + "-01.png";
|
|
|
|
scriptLines.append("set term png size " + QString::number(width) + "," + QString::number(height));
|
|
scriptLines.append("set output '" + originalImageName + "'");
|
|
scriptLines.append("set datafile separator ','");
|
|
scriptLines.append(plotOriginalData(powerBalanceLogs.count()));
|
|
|
|
if (spotMarketEnabled) {
|
|
scriptLines.append("set term png size " + QString::number(width) + "," + QString::number(height * 2));
|
|
scriptLines.append("set output '" + simulationImageName + "'");
|
|
scriptLines.append("set datafile separator ','");
|
|
|
|
scriptLines.append("set multiplot layout 2,1");
|
|
|
|
scriptLines.append("set size 1,0.8");
|
|
scriptLines.append("set origin 0,0.2");
|
|
scriptLines.append(plotSimulation(simulationTitle, powerBalanceLogs.count()));
|
|
|
|
scriptLines.append("set size 1,0.2");
|
|
scriptLines.append("set origin 0,0");
|
|
scriptLines.append(plotSpotMarketData(powerBalanceLogs.count()));
|
|
|
|
scriptLines.append("unset multiplot");
|
|
|
|
} else {
|
|
scriptLines.append("set term png size " + QString::number(width) + "," + QString::number(height));
|
|
scriptLines.append("set output '" + simulationImageName + "'");
|
|
scriptLines.append("set datafile separator ','");
|
|
scriptLines.append(plotSimulation(simulationTitle, powerBalanceLogs.count()));
|
|
}
|
|
|
|
// Write the gnuplot script
|
|
QFile gnuplotScript(outputDir.path() + QDir::separator() + "script.gnuplot");
|
|
QVERIFY2(gnuplotScript.open(QIODevice::ReadWrite | QIODevice::Truncate),
|
|
QString("Failed to open script file for gnuplot" + gnuplotScript.fileName() + ": " + gnuplotScript.errorString()).toUtf8());
|
|
QTextStream scriptStream(&gnuplotScript);
|
|
foreach (const QString &line, scriptLines)
|
|
scriptStream << line << "\n";
|
|
|
|
gnuplotScript.close();
|
|
|
|
|
|
// Write the executable gnuplot script
|
|
|
|
scriptLines.clear();
|
|
|
|
scriptLines.append("set terminal wxt 1 persist");
|
|
scriptLines.append("set datafile separator ','");
|
|
|
|
if (spotMarketEnabled) {
|
|
|
|
scriptLines.append("set multiplot layout 2,1");
|
|
|
|
scriptLines.append("set size 1,0.8");
|
|
scriptLines.append("set origin 0,0.2");
|
|
scriptLines.append(plotSimulation(simulationTitle, powerBalanceLogs.count()));
|
|
|
|
scriptLines.append("set size 1,0.2");
|
|
scriptLines.append("set origin 0,0");
|
|
scriptLines.append(plotSpotMarketData(powerBalanceLogs.count()));
|
|
|
|
scriptLines.append("unset multiplot");
|
|
|
|
} else {
|
|
scriptLines.append(plotSimulation(simulationTitle, powerBalanceLogs.count()));
|
|
}
|
|
|
|
QString executableScriptName = simulationName + ".gnuplot";
|
|
QFile executableGnuplotScript(outputDir.path() + QDir::separator() + executableScriptName);
|
|
QVERIFY2(executableGnuplotScript.open(QIODevice::ReadWrite | QIODevice::Truncate),
|
|
QString("Failed to open logfile for gnuplot" + executableGnuplotScript.fileName() + ": " + executableGnuplotScript.errorString()).toUtf8());
|
|
QTextStream executableScriptStream(&executableGnuplotScript);
|
|
foreach (const QString &line, scriptLines)
|
|
executableScriptStream << line << "\n";
|
|
|
|
executableGnuplotScript.close();
|
|
|
|
|
|
|
|
QProcess gnuplotProcess;
|
|
//gnuplotProcess.setEnvironment(QProcessEnvironment::systemEnvironment().toStringList());
|
|
gnuplotProcess.setProcessChannelMode(QProcess::MergedChannels);
|
|
gnuplotProcess.setWorkingDirectory(outputDir.path());
|
|
gnuplotProcess.start("gnuplot", { "-c", "script.gnuplot"});
|
|
gnuplotProcess.waitForFinished();
|
|
qCDebug(dcSimulation()) << "gnuplot finished" << gnuplotProcess.arguments() << gnuplotProcess.workingDirectory() << gnuplotProcess.exitCode() << gnuplotProcess.exitStatus();
|
|
if (gnuplotProcess.exitCode() != 0) {
|
|
qCDebug(dcSimulation()) << "error plotting data:\n" << qUtf8Printable(gnuplotProcess.readAll());
|
|
QVERIFY2(false, "plot process finished with error");
|
|
}
|
|
|
|
// Copy resulting images to the simulations
|
|
QFile::copy(outputDir.path() + QDir::separator() + originalImageName, resultsDir.path() + QDir::separator() + originalImageName);
|
|
QFile::copy(outputDir.path() + QDir::separator() + simulationImageName, resultsDir.path() + QDir::separator() + simulationImageName);
|
|
}
|
|
|
|
void Simulation::printStates(Thing *thing)
|
|
{
|
|
qCDebug(dcSimulation()) << "Thing states for" << thing->name();
|
|
foreach (const StateType &stateType, thing->thingClass().stateTypes()) {
|
|
qCDebug(dcSimulation()) << "-->" << stateType.name() << thing->stateValue(stateType.id());
|
|
}
|
|
}
|
|
|
|
void Simulation::updateChargerMeter(Thing *thing)
|
|
{
|
|
Action updateChargerAction(thing->thingClass().actionTypes().findByName("update").id(), thing->id());
|
|
NymeaCore::instance()->thingManager()->executeAction(updateChargerAction);
|
|
}
|
|
|
|
QStringList Simulation::plotOriginalData(int powerBalanceCount)
|
|
{
|
|
QStringList scriptLines;
|
|
scriptLines.append("set title 'Original energy data'");
|
|
scriptLines.append("set grid");
|
|
|
|
scriptLines.append("set timefmt '%s'");
|
|
scriptLines.append("set xdata time");
|
|
scriptLines.append("set xtics 3600");
|
|
scriptLines.append("set format x '%H:%M'");
|
|
|
|
scriptLines.append("set xlabel 'Time'");
|
|
scriptLines.append("set ylabel '[W]'");
|
|
|
|
scriptLines.append("set style fill transparent solid 0.3");
|
|
|
|
scriptLines.append("set x2tics 100");
|
|
scriptLines.append("set xtics nomirror");
|
|
scriptLines.append("set x2label 'iterations'");
|
|
scriptLines.append("set x2range [0:" + QString::number(powerBalanceCount) + "]");
|
|
|
|
QStringList plotLines;
|
|
plotLines.append("'original.csv' using 1:3 with boxes lt rgb '#7F75C23A' title 'Production'");
|
|
plotLines.append("'original.csv' using 1:4 with boxes lt rgb '#7F3590F3' title 'Consumption'");
|
|
plotLines.append("'original.csv' using 1:5 with line lt rgb 'orange' title 'House limit'");
|
|
plotLines.append("'original.csv' using 1:2 with line lt rgb 'red' title 'Meter'");
|
|
scriptLines.append("plot \\\n" + plotLines.join(", \\\n"));
|
|
scriptLines.append("");
|
|
return scriptLines;
|
|
}
|
|
|
|
QStringList Simulation::plotSimulation(const QString &title, int powerBalanceCount)
|
|
{
|
|
QStringList scriptLines;
|
|
scriptLines.append("set title '" + title + "'");
|
|
scriptLines.append("set grid");
|
|
|
|
scriptLines.append("set timefmt '%s'");
|
|
scriptLines.append("set xdata time");
|
|
scriptLines.append("set format x '%H:%M'");
|
|
scriptLines.append("set xtics 3600");
|
|
|
|
scriptLines.append("set xlabel 'time'");
|
|
scriptLines.append("set ylabel '[W]'");
|
|
|
|
scriptLines.append("set x2tics 100");
|
|
scriptLines.append("set xtics nomirror");
|
|
scriptLines.append("set x2label 'iterations'");
|
|
scriptLines.append("set x2range [0:" + QString::number(powerBalanceCount) + "]");
|
|
|
|
scriptLines.append("set style fill transparent solid 0.3");
|
|
|
|
scriptLines.append("set y2tics 10");
|
|
scriptLines.append("set ytics nomirror");
|
|
scriptLines.append("set y2label '[\%]'");
|
|
scriptLines.append("set y2range [0:100]");
|
|
|
|
QStringList plotLines;
|
|
plotLines.append("'simulation.csv' using 1:9 title 'Charger range' w filledcurves x1 lc rgb '#fff0f0f0'");
|
|
plotLines.append("'simulation.csv' using 1:8 notitle w filledcurves x1 lc rgb '#ffffffff'");
|
|
|
|
plotLines.append("'simulation.csv' using 1:3 with boxes lt rgb '#0A75C23A' title 'Production'");
|
|
plotLines.append("'simulation.csv' using 1:4 with boxes lt rgb '#7F3590F3' title 'Consumption'");
|
|
plotLines.append("'simulation.csv' using 1:17 with boxes lt rgb '#7FA020F0' title 'Energy storage'");
|
|
plotLines.append("'simulation.csv' using 1:5 with boxes lt rgb '#7FF3DE8A' title 'Charger'");
|
|
|
|
// plotLines.append("'simulation.csv' using 1:9 with line lt rgb '#EABC01' title 'Charger max'");
|
|
// plotLines.append("'simulation.csv' using 1:8 with line lt rgb '#F6CAAF' title 'Charger min'");
|
|
|
|
plotLines.append("'simulation.csv' using 1:13 with line lt rgb 'green' title 'Acquisition Limit'");
|
|
plotLines.append("'simulation.csv' using 1:11 with line lt rgb 'black' axes x1y2 title 'Battery [\%]'");
|
|
plotLines.append("'simulation.csv' using 1:18 with line lt rgb 'purple ' axes x1y2 title 'Energy storage [\%]'");
|
|
plotLines.append("'simulation.csv' using 1:14 with line lt rgb 'purple' axes x1y2 title 'Car plugged in into charger'");
|
|
plotLines.append("'simulation.csv' using 1:10 with line lt rgb 'orange' title 'House limit'");
|
|
plotLines.append("'simulation.csv' using 1:2 with line lt rgb 'red' title 'Meter'");
|
|
|
|
scriptLines.append("plot \\\n" + plotLines.join(", \\\n"));
|
|
scriptLines.append("");
|
|
return scriptLines;
|
|
}
|
|
|
|
QStringList Simulation::plotSpotMarketData(int powerBalanceCount)
|
|
{
|
|
QStringList scriptLines;
|
|
scriptLines.append("set title 'Spot maket data'");
|
|
scriptLines.append("set grid");
|
|
|
|
scriptLines.append("set timefmt '%s'");
|
|
scriptLines.append("set xdata time");
|
|
scriptLines.append("set format x '%H:%M'");
|
|
scriptLines.append("set xtics 3600");
|
|
|
|
scriptLines.append("set xlabel 'Time'");
|
|
scriptLines.append("set ylabel 'Price [Cent/kWh]'");
|
|
scriptLines.append("set x2tics 100");
|
|
scriptLines.append("set xtics nomirror");
|
|
scriptLines.append("set x2label 'iterations'");
|
|
scriptLines.append("set x2range [0:" + QString::number(powerBalanceCount) + "]");
|
|
|
|
scriptLines.append("set y2tics");
|
|
scriptLines.append("set ytics nomirror");
|
|
scriptLines.append("set y2label '[\%]'");
|
|
scriptLines.append("set y2range [0:100]");
|
|
|
|
QStringList plotLines;
|
|
plotLines.append("'simulation.csv' using 1:15 with boxes fs solid lt rgb '#fff0f0f0' axes x1y2 title 'Spotmarket scoring [%]'");
|
|
plotLines.append("'simulation.csv' using 1:16 with line lt rgb 'black' axes x1y1 title 'Price [Cent/kWh]'");
|
|
scriptLines.append("plot \\\n" + plotLines.join(", \\\n"));
|
|
scriptLines.append("");
|
|
return scriptLines;
|
|
}
|
|
|
|
|
|
QTEST_MAIN(Simulation)
|