-
Notifications
You must be signed in to change notification settings - Fork 186
[WIP] Fix smart charger OCTT test cases #424
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
3b1759e
3433ea1
c2d84c0
350c818
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53,7 +53,7 @@ void SmartChargingConnector::calculateLimit(const Timestamp &t, ChargeRate& limi | |
| } | ||
|
|
||
| //if no TxProfile limits charging, check the TxDefaultProfiles for this connector | ||
| if (!txLimitDefined && trackTxStart < MAX_TIME) { | ||
| if (!txLimitDefined) { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This fixes the composite schedules. But also affects the ordinary charge limit output if no transaction is running. I cannot think of scenarios where this would be super bad though. The usage of the global Looks good for now! |
||
| for (int i = MO_ChargeProfileMaxStackLevel; i >= 0; i--) { | ||
| if (TxDefaultProfile[i]) { | ||
| ChargeRate crOut; | ||
|
|
@@ -68,7 +68,7 @@ void SmartChargingConnector::calculateLimit(const Timestamp &t, ChargeRate& limi | |
| } | ||
|
|
||
| //if no appropriate TxDefaultProfile is set for this connector, search in the general TxDefaultProfiles | ||
| if (!txLimitDefined && trackTxStart < MAX_TIME) { | ||
| if (!txLimitDefined) { | ||
| for (int i = MO_ChargeProfileMaxStackLevel; i >= 0; i--) { | ||
| if (ChargePointTxDefaultProfile[i]) { | ||
| ChargeRate crOut; | ||
|
|
@@ -168,19 +168,19 @@ void SmartChargingConnector::loop(){ | |
| MO_DBG_INFO("New limit for connector %u, scheduled at = %s, nextChange = %s, limit = {%.1f, %.1f, %i}", | ||
| connectorId, | ||
| timestamp1, timestamp2, | ||
| limit.power != std::numeric_limits<float>::max() ? limit.power : -1.f, | ||
| limit.current != std::numeric_limits<float>::max() ? limit.current : -1.f, | ||
| limit.nphases != std::numeric_limits<int>::max() ? limit.nphases : -1); | ||
| limit.power != std::numeric_limits<float>::max() ? limit.power : MO_MaxChargingLimitPower, | ||
| limit.current != std::numeric_limits<float>::max() ? limit.current : MO_MaxChargingLimitCurrent, | ||
| limit.nphases != std::numeric_limits<int>::max() ? limit.nphases : MO_MaxChargingLimitNumberPhases); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be nice to preserve the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But do you really think it matters? What would the user-land code do? it still needs to set that limit on the PWM duty-cycle, no matter if default or set. Anyhow, do you have an idea how to preserve this AND also keep the fixes for OCTT? It would be strange to use those defs only in
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For sure it doesn't matter much. There are few edge cases I can think of:
On the other hand, negative values as undefined values are easy to understand. And the application firmware needs some logic to sanitize the values anyway, because MO doesn't do a range check (you could define a 100A limit on a 32A charger at the moment). The GetCompositeSchedule use case alone is a super valid reason to add a new build flag. Maybe a name like |
||
| } | ||
| #endif | ||
|
|
||
| if (trackLimitOutput != limit) { | ||
| if (limitOutput) { | ||
|
|
||
| limitOutput( | ||
| limit.power != std::numeric_limits<float>::max() ? limit.power : -1.f, | ||
| limit.current != std::numeric_limits<float>::max() ? limit.current : -1.f, | ||
| limit.nphases != std::numeric_limits<int>::max() ? limit.nphases : -1); | ||
| limit.power != std::numeric_limits<float>::max() ? limit.power : MO_MaxChargingLimitPower, | ||
| limit.current != std::numeric_limits<float>::max() ? limit.current : MO_MaxChargingLimitCurrent, | ||
| limit.nphases != std::numeric_limits<int>::max() ? limit.nphases : MO_MaxChargingLimitNumberPhases); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above |
||
| trackLimitOutput = limit; | ||
| } | ||
| } | ||
|
|
@@ -252,6 +252,9 @@ std::unique_ptr<ChargingSchedule> SmartChargingConnector::getCompositeSchedule(i | |
| Timestamp periodBegin = Timestamp(startSchedule); | ||
| Timestamp periodStop = Timestamp(startSchedule); | ||
|
|
||
| //remember last effective limit we actually *emitted* | ||
| ChargeRate lastLimit; | ||
|
|
||
| while (periodBegin - startSchedule < duration && periods.size() < MO_ChargingScheduleMaxPeriods) { | ||
|
|
||
| //calculate limit | ||
|
|
@@ -267,11 +270,16 @@ std::unique_ptr<ChargingSchedule> SmartChargingConnector::getCompositeSchedule(i | |
| } | ||
| } | ||
|
|
||
| periods.emplace_back(); | ||
| float limit_opt = unit == ChargingRateUnitType_Optional::Watt ? limit.power : limit.current; | ||
| periods.back().limit = limit_opt != std::numeric_limits<float>::max() ? limit_opt : -1.f, | ||
| periods.back().numberPhases = limit.nphases != std::numeric_limits<int>::max() ? limit.nphases : -1; | ||
| periods.back().startPeriod = periodBegin - startSchedule; | ||
| //coalesce: only push when the effective limit actually *changes* | ||
| if (periods.empty() || limit != lastLimit) { | ||
| periods.emplace_back(); | ||
| float limit_opt = unit == ChargingRateUnitType_Optional::Watt ? limit.power : limit.current; | ||
| float fallback_limit = unit == ChargingRateUnitType_Optional::Watt ? MO_MaxChargingLimitPower : MO_MaxChargingLimitCurrent; | ||
| periods.back().limit = limit_opt != std::numeric_limits<float>::max() ? limit_opt : fallback_limit; | ||
| periods.back().numberPhases = limit.nphases != std::numeric_limits<int>::max() ? limit.nphases : MO_MaxChargingLimitNumberPhases; | ||
| periods.back().startPeriod = periodBegin - startSchedule; | ||
| lastLimit = limit; | ||
| } | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! |
||
|
|
||
| periodBegin = periodStop; | ||
| } | ||
|
|
@@ -521,19 +529,19 @@ void SmartChargingService::loop(){ | |
| MO_DBG_INFO("New limit for connector %u, scheduled at = %s, nextChange = %s, limit = {%.1f, %.1f, %i}", | ||
| 0, | ||
| timestamp1, timestamp2, | ||
| limit.power != std::numeric_limits<float>::max() ? limit.power : -1.f, | ||
| limit.current != std::numeric_limits<float>::max() ? limit.current : -1.f, | ||
| limit.nphases != std::numeric_limits<int>::max() ? limit.nphases : -1); | ||
| limit.power != std::numeric_limits<float>::max() ? limit.power : MO_MaxChargingLimitPower, | ||
| limit.current != std::numeric_limits<float>::max() ? limit.current : MO_MaxChargingLimitCurrent, | ||
| limit.nphases != std::numeric_limits<int>::max() ? limit.nphases : MO_MaxChargingLimitNumberPhases); | ||
| } | ||
| #endif | ||
|
|
||
| if (trackLimitOutput != limit) { | ||
| if (limitOutput) { | ||
|
|
||
| limitOutput( | ||
| limit.power != std::numeric_limits<float>::max() ? limit.power : -1.f, | ||
| limit.current != std::numeric_limits<float>::max() ? limit.current : -1.f, | ||
| limit.nphases != std::numeric_limits<int>::max() ? limit.nphases : -1); | ||
| limit.power != std::numeric_limits<float>::max() ? limit.power : MO_MaxChargingLimitPower, | ||
| limit.current != std::numeric_limits<float>::max() ? limit.current : MO_MaxChargingLimitCurrent, | ||
| limit.nphases != std::numeric_limits<int>::max() ? limit.nphases : MO_MaxChargingLimitNumberPhases); | ||
| trackLimitOutput = limit; | ||
| } | ||
| } | ||
|
|
@@ -692,8 +700,9 @@ std::unique_ptr<ChargingSchedule> SmartChargingService::getCompositeSchedule(uns | |
|
|
||
| periods.push_back(ChargingSchedulePeriod()); | ||
| float limit_opt = unit == ChargingRateUnitType_Optional::Watt ? limit.power : limit.current; | ||
| periods.back().limit = limit_opt != std::numeric_limits<float>::max() ? limit_opt : -1.f; | ||
| periods.back().numberPhases = limit.nphases != std::numeric_limits<int>::max() ? limit.nphases : -1; | ||
| float fallback_limit = unit == ChargingRateUnitType_Optional::Watt ? MO_MaxChargingLimitPower : MO_MaxChargingLimitCurrent; | ||
| periods.back().limit = limit_opt != std::numeric_limits<float>::max() ? limit_opt : fallback_limit; | ||
| periods.back().numberPhases = limit.nphases != std::numeric_limits<int>::max() ? limit.nphases : MO_MaxChargingLimitNumberPhases; | ||
| periods.back().startPeriod = periodBegin - startSchedule; | ||
|
|
||
| periodBegin = periodStop; | ||
|
|
@@ -764,6 +773,8 @@ bool SmartChargingServiceUtils::removeProfile(std::shared_ptr<FilesystemAdapter> | |
| return false; | ||
| } | ||
|
|
||
| MO_DBG_DEBUG("Removing chargingProfile for connector %d, purpose %d, stack level %d, file %s", connectorId, (int) purpose, (int) stackLevel, fn); | ||
|
|
||
| return filesystem->remove(fn); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,21 @@ | |
| #ifndef SMARTCHARGINGSERVICE_H | ||
| #define SMARTCHARGINGSERVICE_H | ||
|
|
||
| // Per OCPP `GetCompositeScheduleResponse` schema, limit must be > 0. | ||
| // Please define a sane value in your implementation (e.g. 32A or 22kW-equivalent) instead of -1 to pass the OCTT tests. | ||
| #ifndef MO_MaxChargingLimitPower | ||
| #define MO_MaxChargingLimitPower -1.f | ||
| #endif | ||
|
|
||
| #ifndef MO_MaxChargingLimitCurrent | ||
| #define MO_MaxChargingLimitCurrent -1.f | ||
| #endif | ||
|
|
||
| // For numberPhases, the field is optional; if unknown you can default to 3 (typical three-phase) instead of -1. | ||
| #ifndef MO_MaxChargingLimitNumberPhases | ||
| #define MO_MaxChargingLimitNumberPhases -1 | ||
| #endif | ||
|
|
||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good and simple solution for most use cases |
||
| #include <functional> | ||
| #include <array> | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!