|
28 | 28 | #include "smart_charging_test_utils.hpp" |
29 | 29 | #include <smart_charging_matchers.hpp> |
30 | 30 |
|
| 31 | +#include <chrono> |
31 | 32 | #include <sstream> |
32 | 33 | #include <vector> |
33 | 34 |
|
@@ -1248,4 +1249,194 @@ TEST_F(CompositeScheduleTestFixtureV2, ZeroDuration) { |
1248 | 1249 | EXPECT_THAT(result.chargingSchedulePeriod, testing::ElementsAre(PeriodEquals(0, expected_limit))); |
1249 | 1250 | } |
1250 | 1251 |
|
| 1252 | +TEST_F(CompositeScheduleTestFixtureV2, OfflineDuration_Online) { |
| 1253 | + this->load_charging_profiles_for_evse(BASE_JSON_PATH_V2 + "/offline_duration/valid_after_offline_duration/", |
| 1254 | + DEFAULT_EVSE_ID); |
| 1255 | + |
| 1256 | + evse_manager->open_transaction(DEFAULT_EVSE_ID, TX_ID); |
| 1257 | + |
| 1258 | + EXPECT_CALL(*database_handler, get_charging_profiles_for_evse(testing::_)).Times(testing::AnyNumber()); |
| 1259 | + EXPECT_CALL(*database_handler, new_statement(testing::_)).Times(testing::AnyNumber()); |
| 1260 | + EXPECT_CALL(evse_manager->get_mock(1), get_current_phase_type).Times(testing::AnyNumber()); |
| 1261 | + |
| 1262 | + const auto start_time = ocpp::DateTime{"2024-01-17T18:00:00"}; |
| 1263 | + const auto end_time = ocpp::DateTime{"2024-01-18T06:00:00"}; |
| 1264 | + |
| 1265 | + // Profile with CentralSetpoint has higher StackLevel and therefore is preferred |
| 1266 | + ChargingSchedulePeriod expected_period{}; |
| 1267 | + expected_period.limit = 2000.0; |
| 1268 | + expected_period.numberPhases = 3; |
| 1269 | + expected_period.setpoint = -2000.0; |
| 1270 | + expected_period.startPeriod = 0; |
| 1271 | + |
| 1272 | + CompositeSchedule expected_schedule{}; |
| 1273 | + expected_schedule.chargingSchedulePeriod = {expected_period}; |
| 1274 | + expected_schedule.evseId = DEFAULT_EVSE_ID; |
| 1275 | + expected_schedule.duration = 43200; |
| 1276 | + expected_schedule.scheduleStart = start_time; |
| 1277 | + expected_schedule.chargingRateUnit = ChargingRateUnitEnum::W; |
| 1278 | + |
| 1279 | + const auto actual_schedule = handler->calculate_composite_schedule(start_time, end_time, DEFAULT_EVSE_ID, |
| 1280 | + ChargingRateUnitEnum::W, false, false); |
| 1281 | + |
| 1282 | + ASSERT_EQ(actual_schedule, expected_schedule); |
| 1283 | +} |
| 1284 | + |
| 1285 | +TEST_F(CompositeScheduleTestFixtureV2, OfflineDuration_OfflineNotLongEnough) { |
| 1286 | + this->load_charging_profiles_for_evse(BASE_JSON_PATH_V2 + "/offline_duration/valid_after_offline_duration/", |
| 1287 | + DEFAULT_EVSE_ID); |
| 1288 | + |
| 1289 | + evse_manager->open_transaction(DEFAULT_EVSE_ID, TX_ID); |
| 1290 | + |
| 1291 | + EXPECT_CALL(*database_handler, get_charging_profiles_for_evse(testing::_)).Times(testing::AnyNumber()); |
| 1292 | + EXPECT_CALL(*database_handler, new_statement(testing::_)).Times(testing::AnyNumber()); |
| 1293 | + EXPECT_CALL(evse_manager->get_mock(1), get_current_phase_type).Times(testing::AnyNumber()); |
| 1294 | + |
| 1295 | + EXPECT_CALL(connectivity_manager, get_time_disconnected()) |
| 1296 | + .WillRepeatedly(testing::Return(std::chrono::steady_clock::now() - std::chrono::seconds(300))); |
| 1297 | + |
| 1298 | + const auto start_time = ocpp::DateTime{"2024-01-17T18:00:00"}; |
| 1299 | + const auto end_time = ocpp::DateTime{"2024-01-18T06:00:00"}; |
| 1300 | + |
| 1301 | + // Profile with CentralSetpoint is preferred, because it is still valid in the offline case |
| 1302 | + ChargingSchedulePeriod expected_period{}; |
| 1303 | + expected_period.limit = 2000.0; |
| 1304 | + expected_period.numberPhases = 3; |
| 1305 | + expected_period.setpoint = -2000.0; |
| 1306 | + expected_period.startPeriod = 0; |
| 1307 | + |
| 1308 | + CompositeSchedule expected_schedule{}; |
| 1309 | + expected_schedule.chargingSchedulePeriod = {expected_period}; |
| 1310 | + expected_schedule.evseId = DEFAULT_EVSE_ID; |
| 1311 | + expected_schedule.duration = 43200; |
| 1312 | + expected_schedule.scheduleStart = start_time; |
| 1313 | + expected_schedule.chargingRateUnit = ChargingRateUnitEnum::W; |
| 1314 | + |
| 1315 | + const auto actual_schedule = handler->calculate_composite_schedule(start_time, end_time, DEFAULT_EVSE_ID, |
| 1316 | + ChargingRateUnitEnum::W, false, false); |
| 1317 | + |
| 1318 | + ASSERT_EQ(actual_schedule, expected_schedule); |
| 1319 | +} |
| 1320 | + |
| 1321 | +TEST_F(CompositeScheduleTestFixtureV2, OfflineDuration_OfflineTooLong) { |
| 1322 | + this->load_charging_profiles_for_evse(BASE_JSON_PATH_V2 + "/offline_duration/valid_after_offline_duration/", |
| 1323 | + DEFAULT_EVSE_ID); |
| 1324 | + |
| 1325 | + evse_manager->open_transaction(DEFAULT_EVSE_ID, TX_ID); |
| 1326 | + |
| 1327 | + EXPECT_CALL(*database_handler, get_charging_profiles_for_evse(testing::_)).Times(testing::AnyNumber()); |
| 1328 | + EXPECT_CALL(*database_handler, new_statement(testing::_)).Times(testing::AnyNumber()); |
| 1329 | + EXPECT_CALL(evse_manager->get_mock(1), get_current_phase_type).Times(testing::AnyNumber()); |
| 1330 | + |
| 1331 | + EXPECT_CALL(connectivity_manager, get_time_disconnected()) |
| 1332 | + .WillRepeatedly(testing::Return(std::chrono::steady_clock::now() - std::chrono::seconds(900))); |
| 1333 | + |
| 1334 | + const auto start_time = ocpp::DateTime{"2024-01-17T18:00:00"}; |
| 1335 | + const auto end_time = ocpp::DateTime{"2024-01-18T06:00:00"}; |
| 1336 | + |
| 1337 | + // Profile with ChargingOnly is preferred, because the other one is invalid now that we have been offline for too |
| 1338 | + // long |
| 1339 | + ChargingSchedulePeriod expected_period{}; |
| 1340 | + expected_period.limit = 2000.0; |
| 1341 | + expected_period.numberPhases = 3; |
| 1342 | + expected_period.startPeriod = 0; |
| 1343 | + |
| 1344 | + CompositeSchedule expected_schedule{}; |
| 1345 | + expected_schedule.chargingSchedulePeriod = {expected_period}; |
| 1346 | + expected_schedule.evseId = DEFAULT_EVSE_ID; |
| 1347 | + expected_schedule.duration = 43200; |
| 1348 | + expected_schedule.scheduleStart = start_time; |
| 1349 | + expected_schedule.chargingRateUnit = ChargingRateUnitEnum::W; |
| 1350 | + |
| 1351 | + const auto actual_schedule = handler->calculate_composite_schedule(start_time, end_time, DEFAULT_EVSE_ID, |
| 1352 | + ChargingRateUnitEnum::W, false, false); |
| 1353 | + |
| 1354 | + ASSERT_EQ(actual_schedule, expected_schedule); |
| 1355 | +} |
| 1356 | + |
| 1357 | +TEST_F(CompositeScheduleTestFixtureV2, OfflineDuration_OfflineTooLong_ValidAfterOfflineDuration) { |
| 1358 | + this->load_charging_profiles_for_evse(BASE_JSON_PATH_V2 + "/offline_duration/valid_after_offline_duration/", |
| 1359 | + DEFAULT_EVSE_ID); |
| 1360 | + |
| 1361 | + evse_manager->open_transaction(DEFAULT_EVSE_ID, TX_ID); |
| 1362 | + |
| 1363 | + EXPECT_CALL(*database_handler, get_charging_profiles_for_evse(testing::_)).Times(testing::AnyNumber()); |
| 1364 | + EXPECT_CALL(*database_handler, new_statement(testing::_)).Times(testing::AnyNumber()); |
| 1365 | + EXPECT_CALL(evse_manager->get_mock(1), get_current_phase_type).Times(testing::AnyNumber()); |
| 1366 | + |
| 1367 | + EXPECT_CALL(connectivity_manager, get_time_disconnected()) |
| 1368 | + .WillRepeatedly(testing::Return(std::chrono::steady_clock::now() - std::chrono::seconds(900))); |
| 1369 | + |
| 1370 | + const auto start_time = ocpp::DateTime{"2024-01-17T18:00:00"}; |
| 1371 | + const auto end_time = ocpp::DateTime{"2024-01-18T06:00:00"}; |
| 1372 | + |
| 1373 | + // Profile with ChargingOnly is preferred after being offline for too long |
| 1374 | + ChargingSchedulePeriod expected_period{}; |
| 1375 | + expected_period.limit = 2000.0; |
| 1376 | + expected_period.numberPhases = 3; |
| 1377 | + expected_period.startPeriod = 0; |
| 1378 | + |
| 1379 | + CompositeSchedule expected_schedule{}; |
| 1380 | + expected_schedule.chargingSchedulePeriod = {expected_period}; |
| 1381 | + expected_schedule.evseId = DEFAULT_EVSE_ID; |
| 1382 | + expected_schedule.duration = 43200; |
| 1383 | + expected_schedule.scheduleStart = start_time; |
| 1384 | + expected_schedule.chargingRateUnit = ChargingRateUnitEnum::W; |
| 1385 | + |
| 1386 | + auto actual_schedule = handler->calculate_composite_schedule(start_time, end_time, DEFAULT_EVSE_ID, |
| 1387 | + ChargingRateUnitEnum::W, false, false); |
| 1388 | + |
| 1389 | + testing::Mock::VerifyAndClearExpectations(&connectivity_manager); |
| 1390 | + |
| 1391 | + ASSERT_EQ(actual_schedule, expected_schedule); |
| 1392 | + |
| 1393 | + EXPECT_CALL(connectivity_manager, get_time_disconnected()).WillRepeatedly(testing::Return(std::nullopt)); |
| 1394 | + |
| 1395 | + // Profile with CentralSetpoint is preferred after being online again |
| 1396 | + expected_period.setpoint = -2000.0; |
| 1397 | + expected_schedule.chargingSchedulePeriod = {expected_period}; |
| 1398 | + |
| 1399 | + actual_schedule = handler->calculate_composite_schedule(start_time, end_time, DEFAULT_EVSE_ID, |
| 1400 | + ChargingRateUnitEnum::W, false, false); |
| 1401 | + |
| 1402 | + ASSERT_EQ(actual_schedule, expected_schedule); |
| 1403 | +} |
| 1404 | + |
| 1405 | +TEST_F(CompositeScheduleTestFixtureV2, OfflineDuration_OfflineTooLong_InvalidAfterOfflineDuration) { |
| 1406 | + this->load_charging_profiles_for_evse(BASE_JSON_PATH_V2 + "/offline_duration/invalid_after_offline_duration/", |
| 1407 | + DEFAULT_EVSE_ID); |
| 1408 | + |
| 1409 | + evse_manager->open_transaction(DEFAULT_EVSE_ID, TX_ID); |
| 1410 | + |
| 1411 | + EXPECT_CALL(*database_handler, get_charging_profiles_for_evse(testing::_)).Times(testing::AnyNumber()); |
| 1412 | + EXPECT_CALL(*database_handler, new_statement(testing::_)).Times(testing::AnyNumber()); |
| 1413 | + EXPECT_CALL(evse_manager->get_mock(1), get_current_phase_type).Times(testing::AnyNumber()); |
| 1414 | + |
| 1415 | + EXPECT_CALL(connectivity_manager, get_time_disconnected()) |
| 1416 | + .WillRepeatedly(testing::Return(std::chrono::steady_clock::now() - std::chrono::seconds(900))); |
| 1417 | + |
| 1418 | + // Profile with invalidAfterOfflineDuration gets cleared when being offline for too long |
| 1419 | + EXPECT_CALL(*database_handler, clear_charging_profiles_matching_criteria(std::optional<int>{3}, testing::_)); |
| 1420 | + |
| 1421 | + const auto start_time = ocpp::DateTime{"2024-01-17T18:00:00"}; |
| 1422 | + const auto end_time = ocpp::DateTime{"2024-01-18T06:00:00"}; |
| 1423 | + |
| 1424 | + ChargingSchedulePeriod expected_period{}; |
| 1425 | + expected_period.limit = 2000.0; |
| 1426 | + expected_period.numberPhases = 3; |
| 1427 | + expected_period.startPeriod = 0; |
| 1428 | + |
| 1429 | + CompositeSchedule expected_schedule{}; |
| 1430 | + expected_schedule.chargingSchedulePeriod = {expected_period}; |
| 1431 | + expected_schedule.evseId = DEFAULT_EVSE_ID; |
| 1432 | + expected_schedule.duration = 43200; |
| 1433 | + expected_schedule.scheduleStart = start_time; |
| 1434 | + expected_schedule.chargingRateUnit = ChargingRateUnitEnum::W; |
| 1435 | + |
| 1436 | + auto actual_schedule = handler->calculate_composite_schedule(start_time, end_time, DEFAULT_EVSE_ID, |
| 1437 | + ChargingRateUnitEnum::W, false, false); |
| 1438 | + |
| 1439 | + ASSERT_EQ(actual_schedule, expected_schedule); |
| 1440 | +} |
| 1441 | + |
1251 | 1442 | } // namespace ocpp::v2 |
0 commit comments