@@ -20,6 +20,7 @@ along with OpenOCPP. If not, see <http://www.gnu.org/licenses/>.
2020#include " Connectors.h"
2121#include " GenericMessageSender.h"
2222#include " IChargePointConfig.h"
23+ #include " IChargePointEventsHandler.h"
2324#include " IOcppConfig.h"
2425#include " Logger.h"
2526#include " WorkerThreadPool.h"
@@ -38,6 +39,7 @@ namespace chargepoint
3839SmartChargingManager::SmartChargingManager (const ocpp::config::IChargePointConfig& stack_config,
3940 ocpp::config::IOcppConfig& ocpp_config,
4041 ocpp::database::Database& database,
42+ IChargePointEventsHandler& events_handler,
4143 ocpp::helpers::ITimerPool& timer_pool,
4244 ocpp::helpers::WorkerThreadPool& worker_pool,
4345 Connectors& connectors,
@@ -48,6 +50,7 @@ SmartChargingManager::SmartChargingManager(const ocpp::config::IChargePointConfi
4850 GenericMessageHandler<GetCompositeScheduleReq, GetCompositeScheduleConf>(GET_COMPOSITE_SCHEDULE_ACTION, messages_converter),
4951 m_stack_config (stack_config),
5052 m_ocpp_config (ocpp_config),
53+ m_events_handler (events_handler),
5154 m_worker_pool (worker_pool),
5255 m_connectors (connectors),
5356 m_profile_db (ocpp_config, database),
@@ -392,6 +395,32 @@ bool SmartChargingManager::handleMessage(const ocpp::messages::GetCompositeSched
392395 break ;
393396 }
394397 }
398+ if (periods.empty ())
399+ {
400+ LOG_INFO << " No charging profiles for the requested period" ;
401+ }
402+
403+ // Get local limitations
404+ ChargingProfile local_profile;
405+ local_profile.chargingProfileId = 0 ;
406+ local_profile.chargingProfileKind = ChargingProfileKindType::Relative;
407+ local_profile.chargingProfilePurpose = ChargingProfilePurposeType::TxDefaultProfile;
408+ local_profile.stackLevel = 0 ;
409+ if (m_events_handler.getLocalLimitationsSchedule (request.connectorId , request.duration , local_profile.chargingSchedule ) &&
410+ !local_profile.chargingSchedule .chargingSchedulePeriod .empty ())
411+ {
412+ // Ensure profile is relative with the requested duration
413+ local_profile.chargingSchedule .startSchedule .clear ();
414+ local_profile.chargingSchedule .duration = request.duration ;
415+
416+ // Merge periods
417+ std::vector<Period> local_periods = getProfilePeriods (connector, local_profile, now, request.duration );
418+ periods = mergeLocalPeriods (periods, local_periods);
419+ }
420+ else
421+ {
422+ LOG_INFO << " No local limitations for the requested period" ;
423+ }
395424
396425 // Create response
397426 if (!periods.empty ())
@@ -767,19 +796,22 @@ std::vector<SmartChargingManager::Period> SmartChargingManager::getProfilePeriod
767796 // Check if the profile is active
768797 bool found = false ;
769798 size_t period = 0 ;
770- if (isProfileActive (connector, profile, period, time_point))
771- {
772- // Profile is active
773- found = true ;
774- }
775- else
799+ if (!profile.chargingSchedule .chargingSchedulePeriod .empty ())
776800 {
777- // Check start of schedule
778- if ((start_of_schedule <= ts_end_of_schedule) && isProfileValid (profile, start_of_schedule))
801+ if (isProfileActive (connector, profile, period, time_point))
802+ {
803+ // Profile is active
804+ found = true ;
805+ }
806+ else
779807 {
780- // Get the first period
781- period = 0 ;
782- found = true ;
808+ // Check start of schedule
809+ if ((start_of_schedule <= ts_end_of_schedule) && isProfileValid (profile, start_of_schedule))
810+ {
811+ // Get the first period
812+ period = 0 ;
813+ found = true ;
814+ }
783815 }
784816 }
785817
@@ -833,13 +865,13 @@ std::vector<SmartChargingManager::Period> SmartChargingManager::getProfilePeriod
833865 return periods;
834866}
835867
836- /* * @brief Merge composite schedule periods */
868+ /* * @brief Merge charging profiles periods */
837869std::vector<SmartChargingManager::Period> SmartChargingManager::mergeProfilePeriods (const std::vector<Period>& ref_periods,
838870 const std::vector<Period>& new_periods)
839871{
840872 std::vector<Period> merged_periods;
841873
842- // Check first merge
874+ // Check if a merge is needed
843875 if (ref_periods.empty ())
844876 {
845877 merged_periods = new_periods;
@@ -964,13 +996,160 @@ std::vector<SmartChargingManager::Period> SmartChargingManager::mergeProfilePeri
964996 }
965997 if (error || (ref_period_index != ref_periods.size ()))
966998 {
967- LOG_ERROR << " Unable to compute the composite schedule due to non continuous profiles periods" ;
999+ LOG_WARNING << " Unable to compute the composite schedule due to non continuous profiles periods" ;
9681000 merged_periods.clear ();
9691001 }
9701002 }
9711003
9721004 return merged_periods;
9731005}
9741006
1007+ /* * @brief Merge local limitations periods */
1008+ std::vector<SmartChargingManager::Period> SmartChargingManager::mergeLocalPeriods (const std::vector<Period>& profiles_periods,
1009+ const std::vector<Period>& local_periods)
1010+ {
1011+ std::vector<Period> merged_periods;
1012+
1013+ // Check if a merge is needed
1014+ if (profiles_periods.empty ())
1015+ {
1016+ merged_periods = local_periods;
1017+ }
1018+ else
1019+ {
1020+ bool offset = false ;
1021+ int local_period_start = 0 ;
1022+ int local_period_start_offset = 0 ;
1023+ size_t profiles_period_index = 0 ;
1024+ for (size_t i = 0 ; i < local_periods.size (); i++)
1025+ {
1026+ // Compute start of current local period
1027+ if (offset)
1028+ {
1029+ offset = false ;
1030+ }
1031+ else
1032+ {
1033+ local_period_start = local_periods[i].start ;
1034+ local_period_start_offset = 0 ;
1035+ }
1036+
1037+ int local_period_end = local_period_start + (local_periods[i].duration - local_period_start_offset);
1038+ // Check if there are profiles periods left
1039+ if (profiles_period_index != profiles_periods.size ())
1040+ {
1041+ if (local_period_end <= profiles_periods[profiles_period_index].start )
1042+ {
1043+ // The whole period is before the profile period
1044+ addMergedPeriod (local_periods[i], merged_periods);
1045+ }
1046+ else if (local_period_start >= profiles_periods[profiles_period_index].start )
1047+ {
1048+ int profiles_period_end =
1049+ profiles_periods[profiles_period_index].start + profiles_periods[profiles_period_index].duration ;
1050+ if (local_period_end <= profiles_period_end)
1051+ {
1052+ // The whole period is included inside the profile period
1053+ Period p;
1054+ p.start = local_period_start;
1055+ p.duration = local_periods[i].duration - local_period_start_offset;
1056+ mergeSetpoint (profiles_periods[profiles_period_index], local_periods[i], p);
1057+ addMergedPeriod (p, merged_periods);
1058+ }
1059+ else
1060+ {
1061+ // The period is across profile periods
1062+ Period p;
1063+ p.start = local_period_start;
1064+ p.duration = profiles_period_end - local_period_start;
1065+ mergeSetpoint (profiles_periods[profiles_period_index], local_periods[i], p);
1066+ addMergedPeriod (p, merged_periods);
1067+
1068+ // Next profiles period but keep working on the same local period
1069+ local_period_start = p.start + p.duration ;
1070+ local_period_start_offset = local_period_start - local_periods[i].start ;
1071+ offset = true ;
1072+ profiles_period_index++;
1073+ i--;
1074+ }
1075+ }
1076+ else
1077+ {
1078+ // A part of the local period which overlapse the profile period
1079+ Period p;
1080+ p.start = local_periods[i].start ;
1081+ p.duration = profiles_periods[profiles_period_index].start - local_periods[i].start ;
1082+ p.setpoint = local_periods[i].setpoint ;
1083+ p.unit = local_periods[i].unit ;
1084+ p.nb_phases = local_periods[i].nb_phases ;
1085+ addMergedPeriod (p, merged_periods);
1086+
1087+ // Keep working on the same local period
1088+ local_period_start = p.start + p.duration ;
1089+ local_period_start_offset = local_period_start - local_periods[i].start ;
1090+ offset = true ;
1091+ i--;
1092+ }
1093+ }
1094+ else
1095+ {
1096+ // A local period without merge
1097+ Period p;
1098+ p.start = local_period_start;
1099+ p.duration = local_periods[i].duration - local_period_start_offset;
1100+ p.setpoint = local_periods[i].setpoint ;
1101+ p.unit = local_periods[i].unit ;
1102+ p.nb_phases = local_periods[i].nb_phases ;
1103+ addMergedPeriod (p, merged_periods);
1104+ }
1105+ }
1106+ }
1107+ return merged_periods;
1108+ }
1109+
1110+ /* * @brief Merge the setpoint of a local limitation and a profile limitation */
1111+ void SmartChargingManager::mergeSetpoint (const Period& profile_period, const Period& local_period, Period& merged_period)
1112+ {
1113+ float profile_setpoint = profile_period.setpoint ;
1114+ if (profile_period.unit != local_period.unit )
1115+ {
1116+ profile_setpoint = convertToUnit (profile_period.setpoint , local_period.unit , profile_period.nb_phases );
1117+ }
1118+ if (local_period.setpoint < profile_setpoint)
1119+ {
1120+ merged_period.setpoint = local_period.setpoint ;
1121+ merged_period.unit = local_period.unit ;
1122+ merged_period.nb_phases = local_period.nb_phases ;
1123+ }
1124+ else
1125+ {
1126+ merged_period.setpoint = profile_period.setpoint ;
1127+ merged_period.unit = profile_period.unit ;
1128+ merged_period.nb_phases = profile_period.nb_phases ;
1129+ }
1130+ }
1131+
1132+ /* * @brief Add a local limitation and profiles limitations merged period */
1133+ void SmartChargingManager::addMergedPeriod (const Period& merged_period, std::vector<Period>& periods)
1134+ {
1135+ if (periods.empty ())
1136+ {
1137+ periods.push_back (merged_period);
1138+ }
1139+ else
1140+ {
1141+ Period& last_period = periods.back ();
1142+ if ((last_period.setpoint == merged_period.setpoint ) && (last_period.unit == merged_period.unit ) &&
1143+ (last_period.nb_phases == merged_period.nb_phases ))
1144+ {
1145+ last_period.duration += merged_period.duration ;
1146+ }
1147+ else
1148+ {
1149+ periods.push_back (merged_period);
1150+ }
1151+ }
1152+ }
1153+
9751154} // namespace chargepoint
9761155} // namespace ocpp
0 commit comments