🔌 🕐  Experiment with an end to end demo of departure time

Let's try to build on #44 to include departure time.
EDIT: Simplified scenarios with a single SASchedule. More complex schedules are tracked in #68
High level scenario using AC L2:

ISO 15118-2 with EIM

plug in the car with no departure time, eamount = 60,000 Wh
receive SASchedule with pmax = 22,080W, max current = 32A, duration = 1 day

ISO 15118-2 with PnC

plug in the car with no departure time, eamount = 60,000 Wh
receive SASchedule with pmax = 22,080W, max current = 32A, duration = 1 day

Grid control only: grid -> CSMS sends a charging profile to the station with:

10A or 6900W starting an hour before the start of the demo and running for 4 hours
plug in the car with no departure time, eamount = 60,000 Wh
receive SASchedule with pmax = 6900W, max current = 10A, duration = 1 day

Car control only: restart EVSE so that prior charge schedule is deleted

plug in the car with departure time of 6 hours (21600 secs), eamount = 60,000 Wh
receive SASchedule with pmax = 10,000W, max current = 15A, duration = 6 hours

Car + grid control: grid -> CSMS sends a charging profile to the station with:

10A or 6900 W starting an hour before the start of the demo and running for 4 hours
plug in the car with departure time of 3 hours (10800 secs), eamount = 60,000 Wh
receive SASchedule with pmax = 6900W, max current = 10A, duration = 3 hours
note that the car does not recieve its requested energy because of the grid control. It only receives 20,700

Real world example: grid -> CSMS sends a charging profile to the station with:

20A or 13,800 W for the next 12 hours (43200 secs, overnight, no sun is shining)
EV plugs in with a requested departure time of 16 hours (57600 secs) and requested energy of 85kWh [1]
receive SASchedule with ~pmax = 5312, max current = 7A, duration = 16 hours~ pmax (float) = 5312.5 (ceil: 5313), max_current = 7.7 (ceil 8), 15.998 hours (ceil 16).

[1] This is a real-life example from our recent trip to Arcata. We got to the hotel at around 8pm with a Tesla that was almost empty. We wanted to walk to a concert the next morning (9am - 11am) and then leave at noon rather than deal with parking at the concert venue. The hotel had validated parking in the public lot, but the charger was not smart, and there was no communication between the network and the hotel - the validated permit was a piece of paper to put on the windshield. So we got a notification at around 6am indicating that we would start getting charged for parking since the charging was complete. In this case, the fast charging was actually bad - my husband had to run down to the lot and move the car right after he woke up.

Note that these are still very simple scenarios that are primarily focused on the communication between the station and the car. Concretely, the following scenarios are out of scope:

EVSE sending NotifyEVChargingNeedsRequest to the CSMS; from our previous investigation, neither MaEVe or Citrine support this properly (https://github.com/EVerest/everest-demo/issues/44#issuecomment-2127702608). And Citrine doesn't work with PnC right now anyway.
EV sending charging profiles as part of PowerDeliveryReq or ChargingStatusReq
Renegotiation of any kind, either between EVSE and EV or fully end to end

There are lots of cool things we can do in terms of renegotiation and I fully agree that is where the power in smart charging is. But we are going to take one step at a time and bring in more and more complex functionality into the demo over time, involving the community, and making sure that it is consistent with what stakeholders expect. The goal of these initial demos is to build interest and engagement and help spearhead those conversations.

From a technical perspective, this demo boils down to the following technical tasks:

plumb through the new options that we need (departure time and requested energy) from the node-red UI through the car simulator to pyjosev to the JSEVManager module so that the correct messages are sent to the EV (@the-bay-kay, similar to https://github.com/EVerest/everest-demo/issues/61#issuecomment-2192648801)
plumb through the charge profiles from OCPP 2.0.1 to the EVSE manager module so that they can be read correctly by the EVSE ISO 15118-2 code (some combination of @shankari @louisg1337 and @drmrd)
update the docker image for the demo (@shankari)

We will update this issue with progress as we work on these tasks

Looking through the patches that I slapped together quickly, the callback in the core module that handles the set limits or charge profile calls from the CSMS is in modules/OCPP201/OCPP201.cpp
which essentially calls
        this->set_external_limits(charging_schedules);
        this->publish_charging_schedules(charging_schedules);

set_external_limits calls this->r_evse_manager.at(evse_id - 1)->call_set_external_limits(limits);
publish_charging_schedules calls publish_charging_schedules on the ocppImplBase base implementation. However, I don't know where that implementation actually is. I do find a default base implementation in modules/OCPP201/ocpp_generic/ocppImpl.hpp/cpp, but there is no implementation of publish_charging_schedules in it

Couple of other notes:

The implementation in modules/OCPP201/OCPP201.cpp seems to be a direct copy of modules/OCPP/OCPP.cpp!!
I don't see any declaration or definition of ocppImplBase. Searching for it gives the pointers and the subclasses, but not the original class. Given the name, I guess that it is the hookup between the module and the library.

Going to focus on the EVSE manager's call_set_external_limits for now since:

That seems most promising
At least I can find it!

That looks like it calls through to the local_energy_limitsvariable in the EvseManager - e.g.
https://github.com/EVerest/everest-core/blob/4b13b10c4b6ba7ae3edf0a9f7ddfdce274a9332a/modules/EvseManager/EvseManager.cpp#L1084
so here's where the ISO messages are sent out
https://github.com/EVerest/everest-core/blob/4b13b10c4b6ba7ae3edf0a9f7ddfdce274a9332a/modules/EvseV2G/iso_server.cpp#L1105
it's a little bit complex, and it looks like we only populate one PMaxSchedule!!
            conn->ctx->evse_v2g_data.evse_sa_schedule_list.SAScheduleTuple.array[0]
                .PMaxSchedule.PMaxScheduleEntry.array[0]
                .RelativeTimeInterval.start = 0;
            conn->ctx->evse_v2g_data.evse_sa_schedule_list.SAScheduleTuple.array[0]
                .PMaxSchedule.PMaxScheduleEntry.array[0]
                .RelativeTimeInterval.duration_isUsed = 1;
            conn->ctx->evse_v2g_data.evse_sa_schedule_list.SAScheduleTuple.array[0]
                .PMaxSchedule.PMaxScheduleEntry.array[0]
                .RelativeTimeInterval.duration = SA_SCHEDULE_DURATION;
            conn->ctx->evse_v2g_data.evse_sa_schedule_list.SAScheduleTuple.array[0]
                .PMaxSchedule.PMaxScheduleEntry.arrayLen = 1;
            conn->ctx->evse_v2g_data.evse_sa_schedule_list.SAScheduleTuple.arrayLen = 1;

Need to add more logs to figure out what is going in here for our current working scenario, and then how we can extend it going forward....

Tracing through the repos to see where we'll need to add DepartureTime.  It helps to know that this is of the type "EVChargeParameterType", and is an optional field of  of the AC_EVChargeParameterType.  Knowing this, we can go through the repos to figure out what needs changed.
It seems there are three variations of the this datatype that are defined:

First, the struct in (ext-openv2g).  I haven't seen any additional references to this struct, keeping an eye open.
Second, we have iso2_AC_EVChargeParameterType, and its corresponding initialization function here

Interestingly, this initialization zero's out the DepartureTime, and does not set any of the other variables

Third, din_AC_EVChargeParameterType/ and its corresponding initialization function here

This init zero's out all of the values of the struct except Departure Time.

Tracing through now to see exactly when these EVChargeParameterTypes are used, should shed some light on exactly where changes are needed

Drawing out a call graph, mostly to make sure I'm not missing anything when tracing through the code.  I'll keep the diagrams updated below a fold, if folks are curious about my process.

 Call Graph

ok so the evse_sa_schedule_list is set in modules/EvseV2G/v2g_ctx.cpp, but I only see one entry being set, and I don't see how it is hooked up to the local_energy_limits.
What I see is that there is a MQTT message to set the limits.

API's set_limit_amps callback calls evse->call_set_external_limits
which seems to have the following callbacks

# grep -rl set_external_limits modules | grep -v OCPP
modules/API/API.cpp
modules/EvseManager/tests/EvseManagerStub.hpp
modules/EvseManager/evse/evse_managerImpl.cpp
modules/EvseManager/evse/evse_managerImpl.hpp
modules/EnergyNode/energy_grid/energyImpl.hpp
modules/EnergyNode/energy_grid/energyImpl.cpp
modules/EnergyNode/external_limits/external_energy_limitsImpl.cpp
modules/EnergyNode/external_limits/external_energy_limitsImpl.hpp

modules/EnergyNode/external_limits/external_energy_limitsImpl.cpp calls mod->signalExternalLimit(value); in modules/EnergyNode/energy_grid/energyImpl.cpp which calls void energyImpl::set_external_limits
In the EVSE manager, I see
void evse_managerImpl::handle_set_external_limits(types::energy::ExternalLimits& value) {
    mod->updateLocalEnergyLimit(value);
}

I do note
    // wait for EnergyManager to assign optimized current on next opimizer run

commented in some logs from the energy manager, let's see how the clamping actually gets passed through...

Tracethrough for a single schedule
024-07-16 14:36:13.203502 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 14:36:14.297764 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 14:36:15.392452 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 14:36:16.565686 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 14:36:17.659685 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W

...

2024-07-16 14:37:52.310423 [INFO] ocpp:OCPP201     :: Received SetChargingProfile: {
    "chargingProfile": {
        "chargingProfileKind": "Absolute",
        "chargingProfilePurpose": "TxDefaultProfile",
        "chargingSchedule": [
            {
                "chargingRateUnit": "A",
                "chargingSchedulePeriod": [
                    {
                        "limit": 20.0,
                        "numberPhases": 3,
                        "startPeriod": 0
                    }
                ],
                "duration": 172800,
                "id": 0,
                "minChargingRate": 0.0,
                "startSchedule": "2024-07-16T00:00:00.000Z"
            }
        ],
        "id": 1,
        "recurrencyKind": "Daily",
        "stackLevel": 1
    },
    "evseId": 0
}
with messageId: 5659bddd-959d-4c5c-9772-e86dae7e742b
2024-07-16 14:37:52.318355 [WARN] ocpp:OCPP201    module::OCPP201::ready()::<lambda()> :: Received a new Charging Schedules from the CSMS or another actor.
2024-07-16 14:37:52.318528 [INFO] ocpp:OCPP201     :: ProfileId #1 Kind: Absolute
2024-07-16 14:37:52.319332 [INFO] ocpp:OCPP201     :: #1 find_period_at> 2024-07-16T00:00:00.000Z
2024-07-16 14:37:52.319439 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T14:37:52.318Z
2024-07-16 14:37:52.319580 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-16T00:00:00.000Z
2024-07-16 14:37:52.319777 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-18T00:00:00.000Z
2024-07-16 14:37:52.319970 [INFO] ocpp:OCPP201     :: PeriodDateTimePair>  period: {
    "limit": 20.0,
    "numberPhases": 3,
    "startPeriod": 0
} end_time: 2024-07-18T00:00:00.000Z
2024-07-16 14:37:52.320061 [INFO] ocpp:OCPP201     :: period.has_value() limit = 13800
2024-07-16 14:37:52.320193 [INFO] ocpp:OCPP201     :: period.has_value() stackLevel = 13800
2024-07-16 14:37:52.320363 [INFO] ocpp:OCPP201     :: ProfileId #1 Kind: Absolute
2024-07-16 14:37:52.320489 [INFO] ocpp:OCPP201     :: #1 find_period_at> 2024-07-16T00:00:00.000Z
2024-07-16 14:37:52.320624 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T14:37:52.320Z
2024-07-16 14:37:52.320751 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-16T00:00:00.000Z
2024-07-16 14:37:52.320814 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-18T00:00:00.000Z
2024-07-16 14:37:52.320938 [INFO] ocpp:OCPP201     :: PeriodDateTimePair>  period: {
    "limit": 20.0,
    "numberPhases": 3,
    "startPeriod": 0
} end_time: 2024-07-18T00:00:00.000Z
2024-07-16 14:37:52.321113 [INFO] ocpp:OCPP201     :: period.has_value() limit = 13800
2024-07-16 14:37:52.321212 [INFO] ocpp:OCPP201     :: period.has_value() stackLevel = 13800
2024-07-16 14:37:52.333571 [WARN] evse_manager_1: virtual void module::evse::evse_managerImpl::handle_set_external_limits(types::energy::ExternalLimits&) :: In the EVSE manager, received external energy limit {
    "schedule_import": [
        {
            "limits_to_leaves": {
                "total_power_W": 13800.0
            },
            "limits_to_root": {},
            "timestamp": "2024-07-16T14:37:52.321Z"
        }
    ]
}
2024-07-16 14:37:52.334509 [WARN] evse_manager_1: bool module::EvseManager::updateLocalEnergyLimit(types::energy::ExternalLimits) :: External limits are lower, applying them {
    "schedule_import": [
        {
            "limits_to_leaves": {
                "total_power_W": 13800.0
            },
            "limits_to_root": {},
            "timestamp": "2024-07-16T14:37:52.321Z"
        }
    ]
}
2024-07-16 14:37:52.368285 [INFO] ocpp:OCPP201     :: Received profile validity: Validsetting response to {
    "status": "Accepted"
}
2024-07-16 14:37:53.115735 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 14:37:54.252971 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 14:39:16.416786 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 14:39:17.550394 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 14:39:18.684171 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 14:39:19.853086 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W

2024-07-16 14:40:00.381452 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Message to encode (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message": {"Header": {"SessionID": "2B978B6FEFEFE5B7"}, "Body": {"ChargeParameterDiscoveryReq": {"RequestedEnergyTransferMode": "AC_three_phase_core", "AC_EVChargeParameter": {"DepartureTime": 0, "EAmount": {"Value": 60, "Multiplier": 0, "Unit": "Wh"}, "EVMaxVoltage": {"Value": 400, "Multiplier": 0, "Unit": "V"}, "EVMaxCurrent": {"Value": 32000, "Multiplier": -3, "Unit": "A"}, "EVMinCurrent": {"Value": 10, "Multiplier": 0, "Unit": "A"}}}}}}

2024-07-16 14:40:01.073155 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Sent ChargeParameterDiscoveryReq2024-07-16 14:40:01.073178 [INFO] iso15118_charge  :: Parameter-phase started

2024-07-16 14:40:01.073333 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Entered state ChargeParameterDiscovery

2024-07-16 14:40:01.075056 [INFO] iso15118_charge  :: Selected energy transfer mode: AC_three_phase_core
2024-07-16 14:40:01.157703 [INFO] evse_manager_1:  ::                                     CAR ISO V2G ChargeParameterDiscoveryReq
2024-07-16 14:40:01.230939 [INFO] evse_manager_1:  :: EVSE ISO V2G ChargeParameterDiscoveryRes
2024-07-16 14:40:01.248810 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 14:40:01.293935 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Decoded message (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message":{"Header":{"SessionID":"2B978B6FEFEFE5B7"},"Body":{"ChargeParameterDiscoveryRes":{"ResponseCode":"OK","EVSEProcessing":"Finished","SAScheduleList":{"SAScheduleTuple":[{"SAScheduleTupleID":1,"PMaxSchedule":{"PMaxScheduleEntry":[{"RelativeTimeInterval":{"start":0,"duration":86400},"PMax":{"Multiplier":0,"Unit":"W","Value":13800}}]}}]},"AC_EVSEChargeParameter":{"AC_EVSEStatus":{"NotificationMaxDelay":0,"EVSENotification":"None","RCD":false},"EVSENominalVoltage":{"Multiplier":-1,"Unit":"V","Value":2300},"EVSEMaxCurrent":{"Multiplier":-1,"Unit":"A","Value":200}}}}}}

Multi schedule
{
    "id": 1,
    "chargingProfileKind": "Absolute",
    "chargingProfilePurpose": "TxDefaultProfile",
    "chargingSchedule": [
        {
            "id": 0,
            "chargingRateUnit": "A",
            "chargingSchedulePeriod": [
                {
                    "limit": 3.0,
                    "numberPhases": 3,
                    "startPeriod": 0
                }
            ],
            "duration": 3600,
            "minChargingRate": 0.0,
            "startSchedule": "2024-07-16T00:00:00.000Z"
        },
        {
            "id": 1,
            "chargingRateUnit": "A",
            "chargingSchedulePeriod": [
                {
                    "limit": 5.0,
                    "numberPhases": 3,
                    "startPeriod": 0
                }
            ],
            "duration": 3600,
            "minChargingRate": 0.0,
            "startSchedule": "2024-07-16T01:00:00.000Z"
        },
        {
            "id": 3,
            "chargingRateUnit": "A",
            "chargingSchedulePeriod": [
                {
                    "limit": 2.0,
                    "numberPhases": 3,
                    "startPeriod": 0
                }
            ],
            "duration": 3600,
            "minChargingRate": 0.0,
            "startSchedule": "2024-07-16T00:02:00.000Z"
        }
    ],
    "recurrencyKind": "Daily",
    "stackLevel": 1
}

Fails with

2024-07-16 15:11:25.227606 [WARN] ocpp:OCPP201    ocpp::DateTime ocpp::v201::SmartChargingHandler::get_next_temp_time(ocpp::DateTime, const std::vectorocpp::v201::ChargingProfile&, int32_t) :: Charging Profiles with more than one ChargingSchedule are not currently supported.

New multi-schedule with multiple periods in the day
2024-07-16 15:15:28.531018 [INFO] ocpp:OCPP201     :: Received SetChargingProfile: {
    "chargingProfile": {
        "chargingProfileKind": "Absolute",
        "chargingProfilePurpose": "TxDefaultProfile",
        "chargingSchedule": [
            {
                "chargingRateUnit": "A",
                "chargingSchedulePeriod": [
                    {
                        "limit": 3.0,
                        "numberPhases": 3,
                        "startPeriod": 0
                    },
                    {
                        "limit": 5.0,
                        "numberPhases": 3,
                        "startPeriod": 3600
                    },
                    {
                        "limit": 2.0,
                        "numberPhases": 3,
                        "startPeriod": 7200
                    }
                ],
                "duration": 86400,
                "id": 0,
                "minChargingRate": 0.0,
                "startSchedule": "2024-07-16T00:00:00.000Z"
            }
        ],
        "id": 1,
        "recurrencyKind": "Daily",
        "stackLevel": 1
    },
    "evseId": 0
}
with messageId: 8077d06f-1e92-4efd-870b-f218202f027e
2024-07-16 15:15:28.532022 [WARN] ocpp:OCPP201    module::OCPP201::ready()::<lambda()> :: Received a new Charging Schedules from the CSMS or another actor.
2024-07-16 15:15:28.532131 [INFO] ocpp:OCPP201     :: ProfileId #1 Kind: Absolute
2024-07-16 15:15:28.532215 [INFO] ocpp:OCPP201     :: #1 find_period_at> 2024-07-16T00:00:00.000Z
2024-07-16 15:15:28.532313 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T15:15:28.532Z
2024-07-16 15:15:28.532505 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-16T00:00:00.000Z
2024-07-16 15:15:28.532597 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-16T01:00:00.000Z
2024-07-16 15:15:28.532651 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T15:15:28.532Z
2024-07-16 15:15:28.532685 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-16T01:00:00.000Z
2024-07-16 15:15:28.532717 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-16T02:00:00.000Z
2024-07-16 15:15:28.532749 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T15:15:28.532Z
2024-07-16 15:15:28.532779 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-16T02:00:00.000Z
2024-07-16 15:15:28.532809 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-17T00:00:00.000Z
2024-07-16 15:15:28.533136 [INFO] ocpp:OCPP201     :: PeriodDateTimePair>  period: {
    "limit": 2.0,
    "numberPhases": 3,
    "startPeriod": 7200
} end_time: 2024-07-17T00:00:00.000Z
2024-07-16 15:15:28.533251 [INFO] ocpp:OCPP201     :: period.has_value() limit = 1380
2024-07-16 15:15:28.533369 [INFO] ocpp:OCPP201     :: period.has_value() stackLevel = 1380
2024-07-16 15:15:28.533584 [INFO] ocpp:OCPP201     :: ProfileId #1 Kind: Absolute
2024-07-16 15:15:28.533635 [INFO] ocpp:OCPP201     :: #1 find_period_at> 2024-07-16T00:00:00.000Z
2024-07-16 15:15:28.533741 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T15:15:28.533Z
2024-07-16 15:15:28.533792 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-16T00:00:00.000Z
2024-07-16 15:15:28.533867 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-16T01:00:00.000Z
2024-07-16 15:15:28.533945 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T15:15:28.533Z
2024-07-16 15:15:28.534005 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-16T01:00:00.000Z
2024-07-16 15:15:28.534089 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-16T02:00:00.000Z
2024-07-16 15:15:28.534194 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T15:15:28.533Z
2024-07-16 15:15:28.534295 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-16T02:00:00.000Z
2024-07-16 15:15:28.534608 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-17T00:00:00.000Z
2024-07-16 15:15:28.534848 [INFO] ocpp:OCPP201     :: PeriodDateTimePair>  period: {
    "limit": 2.0,
    "numberPhases": 3,
    "startPeriod": 7200
} end_time: 2024-07-17T00:00:00.000Z
2024-07-16 15:15:28.534933 [INFO] ocpp:OCPP201     :: period.has_value() limit = 1380
2024-07-16 15:15:28.534985 [INFO] ocpp:OCPP201     :: period.has_value() stackLevel = 1380
2024-07-16 15:15:28.538997 [WARN] evse_manager_1: virtual void module::evse::evse_managerImpl::handle_set_external_limits(types::energy::ExternalLimits&) :: In the EVSE manager, received external energy limit {
    "schedule_import": [
        {
            "limits_to_leaves": {
                "total_power_W": 1380.0
            },
            "limits_to_root": {},
            "timestamp": "2024-07-16T15:15:28.535Z"
        }
    ]
}
2024-07-16 15:15:28.539186 [WARN] evse_manager_1: bool module::EvseManager::updateLocalEnergyLimit(types::energy::ExternalLimits) :: External limits are lower, applying them {
    "schedule_import": [
        {
            "limits_to_leaves": {
                "total_power_W": 1380.0
            },
            "limits_to_root": {},
            "timestamp": "2024-07-16T15:15:28.535Z"
        }
    ]
}
2024-07-16 15:15:28.578860 [INFO] ocpp:OCPP201     :: Received profile validity: Validsetting response to {
    "status": "Accepted"
}
2024-07-16 15:15:28.597725 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 15:15:29.649187 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 0A 0W
2024-07-16 15:15:30.746741 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 0A 0W
2024-07-16 15:15:31.866096 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 0A 0W

But now the limits are set to 0A. Why? It looks like it finds the correct period. I bet it is because the current is below the min (should add logs to verify). But for now, we can just bump up the amps....

Bumping up the amps by x 10, we get the correct limits, but the last period is the one that is valid.
2024-07-16 15:21:51.526192 [INFO] ocpp:OCPP201     :: period.has_value() limit = 13800
2024-07-16 15:21:51.526250 [INFO] ocpp:OCPP201     :: period.has_value() stackLevel = 13800
2024-07-16 15:21:51.526477 [INFO] ocpp:OCPP201     :: ProfileId #1 Kind: Absolute
2024-07-16 15:21:51.526591 [INFO] ocpp:OCPP201     :: #1 find_period_at> 2024-07-16T00:00:00.000Z
2024-07-16 15:21:51.527036 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T15:21:51.526Z
2024-07-16 15:21:51.527216 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-16T00:00:00.000Z
2024-07-16 15:21:51.527319 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-16T01:00:00.000Z
2024-07-16 15:21:51.527469 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T15:21:51.526Z
2024-07-16 15:21:51.527539 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-16T01:00:00.000Z
2024-07-16 15:21:51.527598 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-16T02:00:00.000Z
2024-07-16 15:21:51.527666 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T15:21:51.526Z
2024-07-16 15:21:51.527724 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-16T02:00:00.000Z
2024-07-16 15:21:51.527968 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-17T00:00:00.000Z
2024-07-16 15:21:51.528132 [INFO] ocpp:OCPP201     :: PeriodDateTimePair>  period: {
    "limit": 20.0,
    "numberPhases": 3,
    "startPeriod": 7200
} end_time: 2024-07-17T00:00:00.000Z
2024-07-16 15:21:51.528224 [INFO] ocpp:OCPP201     :: period.has_value() limit = 13800
2024-07-16 15:21:51.528338 [INFO] ocpp:OCPP201     :: period.has_value() stackLevel = 13800
2024-07-16 15:21:51.571891 [WARN] evse_manager_1: virtual void module::evse::evse_managerImpl::handle_set_external_limits(types::energy::ExternalLimits&) :: In the EVSE manager, received external energy limit {
    "schedule_import": [
        {
            "limits_to_leaves": {
                "total_power_W": 13800.0
            },
            "limits_to_root": {},
            "timestamp": "2024-07-16T15:21:51.528Z"
        }
    ]
}
2024-07-16 15:21:51.572105 [WARN] evse_manager_1: bool module::EvseManager::updateLocalEnergyLimit(types::energy::ExternalLimits) :: External limits are lower, applying them {
    "schedule_import": [
        {
            "limits_to_leaves": {
                "total_power_W": 13800.0
            },
            "limits_to_root": {},
            "timestamp": "2024-07-16T15:21:51.528Z"
        }
    ]
}
2024-07-16 15:21:51.575528 [INFO] ocpp:OCPP201     :: Received profile validity: Validsetting response to {
    "status": "Accepted"
}
2024-07-16 15:21:51.702667 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 0A 0W
2024-07-16 15:21:52.798328 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:21:53.895156 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:21:54.989252 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:21:56.125233 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:21:57.224404 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:21:58.360300 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:21:59.418406 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:00.591170 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:01.687073 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:02.780232 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:03.833069 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:04.968330 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:06.106089 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:07.162219 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:08.219222 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:09.352950 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:10.446061 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:11.608998 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:12.702205 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:13.757494 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:14.811088 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:15.905048 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:16.999038 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:18.093100 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:19.188310 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:20.282066 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:21.376391 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:22.470083 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:23.566002 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:24.675210 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:25.730184 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:26.828686 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W
2024-07-16 15:22:27.967246 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 20A 13800W

Let's adjust the start time so that we can have multiple future schedules
2024-07-16 15:25:43.591721 [INFO] ocpp:OCPP201     :: ProfileId #1 Kind: Absolute
2024-07-16 15:25:43.591783 [INFO] ocpp:OCPP201     :: #1 find_period_at> 2024-07-16T15:00:00.000Z
2024-07-16 15:25:43.592335 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T15:25:43.591Z
2024-07-16 15:25:43.592509 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-16T15:00:00.000Z
2024-07-16 15:25:43.592693 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-16T16:00:00.000Z
2024-07-16 15:25:43.592939 [INFO] ocpp:OCPP201     :: PeriodDateTimePair>  period: {
    "limit": 10.0,
    "numberPhases": 3,
    "startPeriod": 0
} end_time: 2024-07-16T16:00:00.000Z
2024-07-16 15:25:43.593056 [INFO] ocpp:OCPP201     :: period.has_value() limit = 6900
2024-07-16 15:25:43.593236 [INFO] ocpp:OCPP201     :: period.has_value() stackLevel = 6900
2024-07-16 15:25:43.593441 [INFO] ocpp:OCPP201     :: ProfileId #1 Kind: Absolute
2024-07-16 15:25:43.593561 [INFO] ocpp:OCPP201     :: #1 find_period_at> 2024-07-16T15:00:00.000Z
2024-07-16 15:25:43.593712 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T15:25:43.593Z
2024-07-16 15:25:43.593909 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-16T15:00:00.000Z
2024-07-16 15:25:43.594291 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-16T16:00:00.000Z
2024-07-16 15:25:43.594567 [INFO] ocpp:OCPP201     :: PeriodDateTimePair>  period: {
    "limit": 10.0,
    "numberPhases": 3,
    "startPeriod": 0
} end_time: 2024-07-16T16:00:00.000Z
2024-07-16 15:25:43.594667 [INFO] ocpp:OCPP201     :: period.has_value() limit = 6900
2024-07-16 15:25:43.594751 [INFO] ocpp:OCPP201     :: period.has_value() stackLevel = 6900
2024-07-16 15:25:43.597813 [WARN] evse_manager_1: virtual void module::evse::evse_managerImpl::handle_set_external_limits(types::energy::ExternalLimits&) :: In the EVSE manager, received external energy limit {
    "schedule_import": [
        {
            "limits_to_leaves": {
                "total_power_W": 6900.0
            },
            "limits_to_root": {},
            "timestamp": "2024-07-16T15:25:43.594Z"
        }
    ]
}
2024-07-16 15:25:43.598107 [WARN] evse_manager_1: bool module::EvseManager::updateLocalEnergyLimit(types::energy::ExternalLimits) :: External limits are lower, applying them {
    "schedule_import": [
        {
            "limits_to_leaves": {
                "total_power_W": 6900.0
            },
            "limits_to_root": {},
            "timestamp": "2024-07-16T15:25:43.594Z"
        }
    ]
}
2024-07-16 15:25:43.638801 [INFO] ocpp:OCPP201     :: Received profile validity: Validsetting response to {
    "status": "Accepted"
}
2024-07-16 15:25:43.696389 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 15:25:44.802562 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 10A 6900W
2024-07-16 15:25:45.948495 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 10A 6900W
2024-07-16 15:25:47.085433 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 10A 6900W
2024-07-16 15:25:48.223086 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 10A 6900W

Now to plug in the car again
2024-07-16 15:27:06.990023 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Message to encode (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message": {"Header": {"SessionID": "42A1CFBD7F36EF7D"}, "Body": {"ChargeParameterDiscoveryReq": {"RequestedEnergyTransferMode": "AC_three_phase_core", "AC_EVChargeParameter": {"DepartureTime": 0, "EAmount": {"Value": 60, "Multiplier": 0, "Unit": "Wh"}, "EVMaxVoltage": {"Value": 400, "Multiplier": 0, "Unit": "V"}, "EVMaxCurrent": {"Value": 32000, "Multiplier": -3, "Unit": "A"}, "EVMinCurrent": {"Value": 10, "Multiplier": 0, "Unit": "A"}}}}}}

2024-07-16 15:27:07.580390 [INFO] iso15118_charge  :: Parameter-phase started2024-07-16 15:27:07.580374 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Sent ChargeParameterDiscoveryReq

2024-07-16 15:27:07.580664 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Entered state ChargeParameterDiscovery

2024-07-16 15:27:07.582664 [INFO] iso15118_charge  :: Selected energy transfer mode: AC_three_phase_core
2024-07-16 15:27:07.624863 [INFO] evse_manager_1:  ::                                     CAR ISO V2G ChargeParameterDiscoveryReq
2024-07-16 15:27:07.626222 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 10A 6900W
2024-07-16 15:27:07.717601 [INFO] evse_manager_1:  :: EVSE ISO V2G ChargeParameterDiscoveryRes
2024-07-16 15:27:08.142249 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Decoded message (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message":{"Header":{"SessionID":"42A1CFBD7F36EF7D"},"Body":{"ChargeParameterDiscoveryRes":{"ResponseCode":"OK","EVSEProcessing":"Finished","SAScheduleList":{"SAScheduleTuple":[{"SAScheduleTupleID":1,"PMaxSchedule":{"PMaxScheduleEntry":[{"RelativeTimeInterval":{"start":0,"duration":86400},"PMax":{"Multiplier":0,"Unit":"W","Value":6900}}]}}]},"AC_EVSEChargeParameter":{"AC_EVSEStatus":{"NotificationMaxDelay":0,"EVSENotification":"None","RCD":false},"EVSENominalVoltage":{"Multiplier":-1,"Unit":"V","Value":2300},"EVSEMaxCurrent":{"Multiplier":-1,"Unit":"A","Value":100}}}}}}

Again, we get a single SA schedule with 6900W for one day (86400 duration).
But we are only requesting 60 Wh. Let's bump that up to 60 kWh and see what happens.

Keeping a tally of the locations I'll need to add DepartureTime. First, just consolidating the iso requirements for my ease of reading...

 15118-2 `DepartureTime` requirements

Figure 5 on page 15 gives a helpful seq. diagram for the ChargeParameterDiscoveryReq(), the message carrying the ChargeParameterType (DepartureTime) payload.

Where implementation is needed:

[ ] EVCC Resumes previous paused V2G Communication [V2G2-742]

Constraints:

[x] If no DepartureTime, the extension should not be included [V2G2-215] (Presumably, this is what we're already doing)
[ ] Sum of individual intervals in PMaxSchedule & SalesTariff in ChargeParamDiscoveryRes shall match the period indicated in DepartureTime ChargeParameterDisoveryReq [V2G2-303]
[x] If no DepartureTime, sum of PMaxSchedule intervals & SalesTariff shall be >= 24 hours [V2G-304] (Likewise, assuming this is the current behavior. Will check later.)
[ ] If the number of SalesTariffEntry elements or PMaxSchedule elements does not cover the entire period of time until Departuretime, the Target Setting EAmmount has not been met and communication has not been finished.  It is the responsibility of the EVCC to request a new SAScheduleList via another ChargeParameterDiscoveryReq type as soon as the last SalesTariffEntry / PMaxSchedule entry becomes active[V2G-305]
[ ] If #(SalesTariffEntry) is not covering until DepartureTime, it is responsibility of EVCC to optimize the schedule

With the info above, it seems we need to send & handle the DepartureTime whenever a ChargeParameterDiscoverReq is being sent.  As I understand it, this will occur (i) when a new session has been started, and (ii) when a session has been resumed after a pause.
Now to hunt down these occurrences in PyEVJosev and JsEvManager.  At a glance, the JsEvManager changes seem like they will be somewhat straightforward...

Changing the defaults in build/dist/libexec/everest/3rd_party/josev/iso15118/secc/states/iso15118_2_states.py to bump up the power and set the departure time to see if it makes a difference...
            p_e_amount: 60000

        departure_time = (
            ev_data_context.departure_time if ev_data_context.departure_time else 21600
        )

 Pnc is now stuck in Authorization Req/Res
2024-07-16 16:03:05.849775 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Message to encode (ns=http://www.w3.org/2000/09/xmldsig#): {"SignedInfo": {"CanonicalizationMethod": {"Algorithm": "http://www.w3.org/TR/canonical-exi/"}, "SignatureMethod": {"Algorithm": "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"}, "Reference": [{"Transforms": {"Transform": [{"Algorithm": "http://www.w3.org/TR/canonical-exi/"}]}, "DigestMethod": {"Algorithm": "http://www.w3.org/2001/04/xmlenc#sha256"}, "DigestValue": "tQU4I0aGz6D6qZtjjNpeLmZV70/6/jWN+Ew7B9cTVq8=", "URI": "#id1"}]}}
2024-07-16 16:03:06.381961 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Message to encode (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message": {"Header": {"SessionID": "1BFEFA7BFFFFF7BB", "Signature": {"SignedInfo": {"CanonicalizationMethod": {"Algorithm": "http://www.w3.org/TR/canonical-exi/"}, "SignatureMethod": {"Algorithm": "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"}, "Reference": [{"Transforms": {"Transform": [{"Algorithm": "http://www.w3.org/TR/canonical-exi/"}]}, "DigestMethod": {"Algorithm": "http://www.w3.org/2001/04/xmlenc#sha256"}, "DigestValue": "tQU4I0aGz6D6qZtjjNpeLmZV70/6/jWN+Ew7B9cTVq8=", "URI": "#id1"}]}, "SignatureValue": {"value": "NmKlHwYsVCQuXgV0tDIzZbNLuDFIMIKMKH1u9Ir3/rR42dqVSB5TXeQHuX97qQOB+MHRPFgTx/bUAPk4Q0xlgw=="}}}, "Body": {"AuthorizationReq": {"Id": "id1", "GenChallenge": "ajHCFwWA+Q8gyoax/ZYwpw=="}}}}
2024-07-16 16:03:06.502111 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 16:03:07.678986 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 16:03:07.763007 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Sent AuthorizationReq
2024-07-16 16:03:07.763968 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Entered state Authorization

2024-07-16 16:03:07.864598 [WARN] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: Response message (type 6) not configured within 98 ms (took 102 ms)
2024-07-16 16:03:07.869701 [INFO] evse_manager_1:  ::                                     CAR ISO V2G AuthorizationReq
2024-07-16 16:03:07.873175 [INFO] evse_manager_1:  :: EVSE ISO V2G AuthorizationRes
2024-07-16 16:03:08.657887 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Decoded message (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message":{"Header":{"SessionID":"1BFEFA7BFFFFF7BB"},"Body":{"AuthorizationRes":{"ResponseCode":"OK","EVSEProcessing":"Ongoing"}}}}
2024-07-16 16:03:08.660089 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: AuthorizationRes received
2024-07-16 16:03:08.665176 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Message to encode (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message": {"Header": {"SessionID": "1BFEFA7BFFFFF7BB"}, "Body": {"AuthorizationReq": {}}}}
2024-07-16 16:03:08.840837 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 16:03:09.604521 [WARN] ocpp:OCPP201    void ocpp::MessageQueue<M>::handle_timeout_or_callerror(const std::optional<ocpp::EnhancedMessage<M> >&) [with M = ocpp::v201::MessageType] :: Message timeout for: TransactionEvent (eeee3f10-332c-49f8-ae6d-d3e8fc46fb87)
2024-07-16 16:03:09.604837 [WARN] ocpp:OCPP201    void ocpp::MessageQueue<M>::handle_timeout_or_callerror(const std::optional<ocpp::EnhancedMessage<M> >&) [with M = ocpp::v201::MessageType] :: Message is transaction related and will therefore be sent again
2024-07-16 16:03:09.611485 [WARN] ocpp:OCPP201    void ocpp::MessageQueue<M>::handle_timeout_or_callerror(const std::optional<ocpp::EnhancedMessage<M> >&) [with M = ocpp::v201::MessageType] :: Attempt: 2/5 will be sent at 2024-07-16T15:46:02.225Z
2024-07-16 16:03:09.861305 [INFO] ocpp:OCPP201     :: Unsolicited client close reason: read limited at 32769 bytes close code: 1009
2024-07-16 16:03:09.861784 [ERRO] ocpp:OCPP201    void ocpp::WebsocketTlsTPM::on_conn_fail() :: OCPP client connection to server failed
2024-07-16 16:03:09.862404 [INFO] ocpp:OCPP201     :: Reconnecting in: 3000ms, attempt: 1
2024-07-16 16:03:10.007064 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 16:03:10.238957 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Sent AuthorizationReq
2024-07-16 16:03:10.242011 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Entered state Authorization
2024-07-16 16:03:10.249295 [INFO] evse_manager_1:  ::                                     CAR ISO V2G AuthorizationReq
2024-07-16 16:03:10.379931 [INFO] evse_manager_1:  :: EVSE ISO V2G AuthorizationRes
2024-07-16 16:03:11.139473 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Decoded message (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message":{"Header":{"SessionID":"1BFEFA7BFFFFF7BB"},"Body":{"AuthorizationRes":{"ResponseCode":"OK","EVSEProcessing":"Ongoing"}}}}
2024-07-16 16:03:11.143823 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: AuthorizationRes received
2024-07-16 16:03:11.145803 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Message to encode (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message": {"Header": {"SessionID": "1BFEFA7BFFFFF7BB"}, "Body": {"AuthorizationReq": {}}}}
2024-07-16 16:03:11.205276 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 16:03:12.418666 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 16:03:12.689119 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Sent AuthorizationReq
2024-07-16 16:03:12.690228 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Entered state Authorization
2024-07-16 16:03:12.695324 [INFO] evse_manager_1:  ::                                     CAR ISO V2G AuthorizationReq
2024-07-16 16:03:12.826622 [INFO] evse_manager_1:  :: EVSE ISO V2G AuthorizationRes
2024-07-16 16:03:12.863556 [INFO] ocpp:OCPP201     :: Connecting to uri: wss://host.docker.internal/ws/cp001 with security-profile 3
2024-07-16 16:03:12.914853 [INFO] evse_security:E  :: Requesting leaf certificate info: CSMS
2024-07-16 16:03:12.924662 [INFO] evse_security:E  :: Found valid leaf: ["/ext/source/build/dist/etc/everest/certs/client/csms/CSMS_LEAF.pem"]
2024-07-16 16:03:12.932135 [WARN] evse_security:E evse_security::GetCertificateInfoResult evse_security::EvseSecurity::get_leaf_certificate_info_internal(evse_security::LeafCertificateType, evse_security::EncodingFormat, bool) :: CSMS leaf requires full bundle, but full bundle not found at path: "/ext/source/build/dist/etc/everest/certs/client/csms"
2024-07-16 16:03:12.991871 [INFO] evse_security:E  :: Building new certificate hierarchy!
2024-07-16 16:03:13.066321 [INFO] evse_security:E  :: Requesting certificate file: [CSMS] file:"/ext/source/build/dist/etc/everest/certs/ca/v2g/V2G_ROOT_CA.pem"
2024-07-16 16:03:13.103639 [INFO] ocpp:OCPP201     :: Loading CA csms bundle to verify server certificate: /ext/source/build/dist/etc/everest/certs/ca/v2g/V2G_ROOT_CA.pem
2024-07-16 16:03:13.408975 [INFO] ocpp:OCPP201     :: LWS connect with info port: [443] address: [host.docker.internal] path: [/ws/cp001] protocol: [ocpp2.0.1]
2024-07-16 16:03:13.518293 [WARN] energy_manager: void module::EnergyManager::enforce_limits(const std::vector<types::energy::EnforcedLimits>&) :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 16:03:13.588124 [INFO] ocpp:OCPP201     :: OCPP client successfully connected to server
2024-07-16 16:03:13.589208 [WARN] ocpp:OCPP201    int ocpp::callback_minimal(lws*, lws_callback_reasons, void*, void*, size_t) :: callback_minimal called, but data->owner is nullptr. Reason: 80
2024-07-16 16:03:13.593802 [WARN] ocpp:OCPP201    int ocpp::callback_minimal(lws*, lws_callback_reasons, void*, void*, size_t) :: callback_minimal called, but data->owner is nullptr. Reason: 75
2024-07-16 16:03:13.595700 [WARN] ocpp:OCPP201    int ocpp::callback_minimal(lws*, lws_callback_reasons, void*, void*, size_t) :: callback_minimal called, but data->owner is nullptr.  Terminating all modules.
2024-07-16 16:08:05.768883 [INFO] manager          :: SIGTERM of child: api (pid: 6257) succeeded.
2024-07-16 16:08:05.774743 [INFO] manager          :: SIGTERM of child: car_simulator_1 (pid: 6259) succeeded.
2024-07-16 16:08:05.784776 [INFO] manager          :: SIGTERM of child: energy_manager (pid: 6260) succeeded.
2024-07-16 16:08:05.840433 [INFO] manager          :: SIGTERM of child: evse_manager_1 (pid: 6261) succeeded.
2024-07-16 16:08:05.840984 [INFO] manager          :: SIGTERM of child: evse_security (pid: 6267) succeeded.
2024-07-16 16:08:05.841217 [INFO] manager          :: SIGTERM of child: grid_connection_point (pid: 6269) succeeded.
2024-07-16 16:08:05.841350 [INFO] manager          :: SIGTERM of child: iso15118_car (pid: 6270) succeeded.
2024-07-16 16:08:05.860398 [INFO] manager          :: SIGTERM of child: iso15118_charger (pid: 6271) succeeded.
2024-07-16 16:08:05.886850 [INFO] manager          :: SIGTERM of child: ocpp (pid: 6272) succeeded.
2024-07-16 16:08:05.899151 [INFO] manager          :: SIGTERM of child: slac (pid: 6273) succeeded.
2024-07-16 16:08:05.900147 [INFO] manager          :: SIGTERM of child: system (pid: 6274) succeeded.
2024-07-16 16:08:05.922880 [INFO] manager          :: SIGTERM of child: token_provider_1 (pid: 6280) succeeded.
2024-07-16 16:08:05.923692 [INFO] manager          :: SIGTERM of child: yeti_driver_1 (pid: 6282) succeeded.
2024-07-16 16:08:05.924463 [CRIT] manager         int boot(const boost::program_options::variables_map&) :: Exiting manager.
/ext/source/build #

Even after reverting changes.
Restarting even further after saving a patch with the logs

Starting with JsEvManager/index.js some observations:

When incorporating, it seems that the we can ignore the following states within the car_statemachine:

"pluggedin", set by the "pause" command (read: plugged in but not charging)
"diode_fail"
"error_e"
"unplugged"

When looking at the remaining states, it seems they call mod.uses.ev_board_support.call.set_cp_state({ cp_state: x}), where x is either CorB`.   I'm not sure this is the right leard, but I believe following calls like this may help figure out where we need to incorperate departureTime.

From what I can gather, the mutation of variables like mod.maxCurrent is handled by external packages -- as such, I don't believe we need to make any other changes to this file beyond setting the default of mod.iso_departure_time = null...

Restarted everything. It works again.

For the record, and to help in debugging again, here's what a successful auth *should* look like
2024-07-16 17:12:49.700348 [INFO] evse_security:E  :: Verifying leaf certificate: MO
2024-07-16 17:12:49.700850 [INFO] evse_security:E  :: Building new certificate hierarchy!
2024-07-16 17:12:49.702983 [INFO] evse_security:E  :: Building new certificate hierarchy!
2024-07-16 17:12:49.708433 [INFO] ocpp:OCPP201     :: Local contract validation result: Valid
2024-07-16 17:12:49.719646 [INFO] ocpp:OCPP201     :: Online: Pass generated OCSP data to CSMS

2024-07-16 17:12:49.839650 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Message to encode (ns=urn:iso:15118:2:2013:MsgDef): {"AuthorizationReq": {"Id": "id1", "GenChallenge": "AW5ao2VeCrL6l0hePq/8Zg=="}}
2024-07-16 17:12:49.899228 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Message to encode (ns=http://www.w3.org/2000/09/xmldsig#): {"SignedInfo": {"CanonicalizationMethod": {"Algorithm": "http://www.w3.org/TR/canonical-exi/"}, "SignatureMethod": {"Algorithm": "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"}, "Reference": [{"Transforms": {"Transform": [{"Algorithm": "http://www.w3.org/TR/canonical-exi/"}]}, "DigestMethod": {"Algorithm": "http://www.w3.org/2001/04/xmlenc#sha256"}, "DigestValue": "9yFpODfSMBDrbQA2T6oQsKv5JFBYvI6b4QbwozA27rw=", "URI": "#id1"}]}}
2024-07-16 17:12:49.951302 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Message to encode (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message": {"Header": {"SessionID": "77EA5F7FD63DFEEF", "Signature": {"SignedInfo": {"CanonicalizationMethod": {"Algorithm": "http://www.w3.org/TR/canonical-exi/"}, "SignatureMethod": {"Algorithm": "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"}, "Reference": [{"Transforms": {"Transform": [{"Algorithm": "http://www.w3.org/TR/canonical-exi/"}]}, "DigestMethod": {"Algorithm": "http://www.w3.org/2001/04/xmlenc#sha256"}, "DigestValue": "9yFpODfSMBDrbQA2T6oQsKv5JFBYvI6b4QbwozA27rw=", "URI": "#id1"}]}, "SignatureValue": {"value": "zrDorSH8GT7q2GQjmvXMzrbu29oYeWB8RzLaDkCRYhfFHD+72BCl/COw3O8Gq4VkIgLK7oCJyFKPVCG2VZjGLA=="}}}, "Body": {"AuthorizationReq": {"Id": "id1", "GenChallenge": "AW5ao2VeCrL6l0hePq/8Zg=="}}}}

2024-07-16 17:12:50.527150 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Sent AuthorizationReq
2024-07-16 17:12:50.527474 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Entered state Authorization
2024-07-16 17:12:50.534481 [INFO] ocpp:OCPP201     :: CSMS idToken status: Accepted
2024-07-16 17:12:50.534584 [INFO] ocpp:OCPP201     :: CSMS certificate status: Accepted
2024-07-16 17:12:50.534605 [ERRO] ocpp:OCPP201    void ocpp::v201::ChargePoint::handle_message(const ocpp::EnhancedMessage<ocpp::v201::MessageType>&) :: Handle_message called: [3,"daafe391-ffef-4980-ad32-84e73d097da3",{"certificateStatus":"Accepted","idTokenInfo":{"status":"Accepted"}}]
2024-07-16 17:12:50.534751 [ERRO] ocpp:OCPP201    void ocpp::v201::ChargePoint::handle_message(const ocpp::EnhancedMessage<ocpp::v201::MessageType>&) :: json_message called: [3,"daafe391-ffef-4980-ad32-84e73d097da3",{"certificateStatus":"Accepted","idTokenInfo":{"status":"Accepted"}}]
2024-07-16 17:12:50.536751 [INFO] auth:Auth        :: Providing authorization to connector#1

2024-07-16 10:12:00 time=2024-07-16T17:12:00.548Z level=INFO msg="POST /api/v0/cs/cp001/setchargingprofile" remote_addr=<IP_ADDRESS>:48446 status=201 bytes=0 duration=2.257924ms
2024-07-16 10:12:00 time=2024-07-16T17:12:00.598Z level=ERROR msg="unable to route message" chargeStationId=cp001 action=SetChargingProfile err="routing request: NotImplemented: SetChargingProfile result not implemented"
2024-07-16 10:12:00 time=2024-07-16T17:12:00.598Z level=ERROR msg="cs/in/ocpp2.0.1/# receive" duration=103.775µs messaging.system=mqtt messaging.consumer.id=manager-GFDaQ messaging.message.payload_size_bytes=588 messaging.operation=receive csId=cp001 ocpp.version=2.0.1 call_result.action=SetChargingProfile messaging.message.conversation_id=edf9ca5f-5875-4bb4-aab7-a556f28f1e60
2024-07-16 10:12:00 time=2024-07-16T17:12:00.598Z level=ERROR msg=exception exception.type=*fmt.wrapError exception.message="routing request: NotImplemented: SetChargingProfile result not implemented"
2024-07-16 10:12:05 time=2024-07-16T17:12:00.547Z level=INFO msg="cs/out/ocpp2.0.1/# publish" duration=1.475038ms messaging.system=mqtt messaging.message.payload_size_bytes=555 messaging.operation=publish messaging.message.conversation_id=edf9ca5f-5875-4bb4-aab7-a556f28f1e60 csId=cp001 call.action=SetChargingProfile
2024-07-16 10:12:25 time=2024-07-16T17:12:25.782Z level=INFO msg="checking for pending charge station certificates changes"
2024-07-16 10:12:25 time=2024-07-16T17:12:25.784Z level=INFO msg="checking for pending charge station settings changes"
2024-07-16 10:12:25 time=2024-07-16T17:12:25.780Z level=INFO msg="sync triggers" duration=4.453844ms sync.trigger.previous="" sync.trigger.count=0
2024-07-16 10:12:45 time=2024-07-16T17:12:42.785Z level=INFO msg="cs/in/ocpp2.0.1/# receive" duration=349.616µs messaging.system=mqtt messaging.consumer.id=manager-GFDaQ messaging.message.payload_size_bytes=191 messaging.operation=receive csId=cp001 ocpp.version=2.0.1 call.action=StatusNotification messaging.message.conversation_id=03fb6a01-6ad1-4677-9c32-c25853c0c574 status.evse_id=1 status.connector_id=1 status.connector_status=Occupied
2024-07-16 10:12:45 time=2024-07-16T17:12:42.785Z level=INFO msg="cs/out/ocpp2.0.1/# publish" duration=72.589µs messaging.system=mqtt messaging.message.payload_size_bytes=98 messaging.operation=publish messaging.message.conversation_id=03fb6a01-6ad1-4677-9c32-c25853c0c574 csId=cp001 call_result.action=StatusNotification
2024-07-16 10:12:50 time=2024-07-16T17:12:50.532Z level=WARN msg="ocsp check" attempt=1 maxAttempts=1 error="parsing ocsp response: asn1: structure error: tags don't match (16 vs {class:0 tag:28 length:33 isCompound:true}) {optional:false explicit:false application:false private:false defaultValue:<nil> tag:<nil> stringType:0 timeType:0 set:false omitEmpty:false} responseASN1 @2"
2024-07-16 10:12:50 time=2024-07-16T17:12:50.611Z level=INFO msg="transaction event" chargeStationId=cp001 transactionId=12ab48fc-820a-4243-8332-e34f2cd52cbe eventType=Started triggerReason=Authorized seqNo=0
2024-07-16 10:12:50 time=2024-07-16T17:12:49.721Z level=INFO msg="cs/in/ocpp2.0.1/# receive" duration=811.00724ms messaging.system=mqtt messaging.consumer.id=manager-GFDaQ messaging.message.payload_size_bytes=948 messaging.operation=receive csId=cp001 ocpp.version=2.0.1 call.action=Authorize messaging.message.conversation_id=daafe391-ffef-4980-ad32-84e73d097da3 authorize.certificate=hash token_auth.id=UKSWI123456789G token_auth.type=eMAID token_auth.status=Accepted authorize.cert_warn="No OCSP, but ignoring for testing purpose." request.status=Accepted
2024-07-16 10:12:50 time=2024-07-16T17:12:49.725Z level=INFO msg="HTTP POST" duration=807.121357ms http.method=POST http.url=https://www.example.com/ net.peer.name=www.example.com http.request_content_length=97 http.status_code=200 http.response_content_length=1256
2024-07-16 10:12:50 time=2024-07-16T17:12:50.532Z level=INFO msg="cs/out/ocpp2.0.1/# publish" duration=88.681µs messaging.system=mqtt messaging.message.payload_size_bytes=155 messaging.operation=publish messaging.message.conversation_id=daafe391-ffef-4980-ad32-84e73d097da3 csId=cp001 call_result.action=Authorize
2024-07-16 10:12:50 time=2024-07-16T17:12:50.610Z level=INFO msg="cs/in/ocpp2.0.1/# receive" duration=11.894652ms messaging.system=mqtt messaging.consumer.id=manager-GFDaQ messaging.message.payload_size_bytes=1605 messaging.operation=receive csId=cp001 ocpp.version=2.0.1 call.action=TransactionEvent messaging.message.conversation_id=193336cd-a66f-437d-92d6-0062a8734ada token_auth.id=UKSWI123456789G token_auth.type=eMAID token_auth.status=Accepted
2024-07-16 10:12:50 time=2024-07-16T17:12:50.622Z level=INFO msg="cs/out/ocpp2.0.1/# publish" duration=73.971µs messaging.system=mqtt messaging.message.payload_size_bytes=131 messaging.operation=publish messaging.message.conversation_id=193336cd-a66f-437d-92d6-0062a8734ada csId=cp001 call_result.action=TransactionEvent
2024-07-16 10:12:52 time=2024-07-16T17:12:52.744Z level=INFO msg="transaction event" chargeStationId=cp001 transactionId=12ab48fc-820a-4243-8332-e34f2cd52cbe eventType=Updated triggerReason=ChargingStateChanged seqNo=1
2024-07-16 10:12:55 time=2024-07-16T17:12:52.743Z level=INFO msg="cs/in/ocpp2.0.1/# receive" duration=9.621107ms messaging.system=mqtt messaging.consumer.id=manager-GFDaQ messaging.message.payload_size_bytes=322 messaging.operation=receive csId=cp001 ocpp.version=2.0.1 call.action=TransactionEvent messaging.message.conversation_id=615822f6-7887-4301-a381-a289e102517a
2024-07-16 10:12:55 time=2024-07-16T17:12:52.752Z level=INFO msg="cs/out/ocpp2.0.1/# publish" duration=122.01µs messaging.system=mqtt messaging.message.payload_size_bytes=96 messaging.operation=publish messaging.message.conversation_id=615822f6-7887-4301-a381-a289e102517a csId=cp001 call_result.action=TransactionEvent

Making the pyjosev changes without adding any other logs
2024-07-16 17:48:36.189938 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Message to encode (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message": {"Header": {"SessionID": "DE20EB55FEFCBC67"}, "Body": {"ChargeParameterDiscoveryReq": {"RequestedEnergyTransferMode": "AC_three_phase_core", "AC_EVChargeParameter": {"DepartureTime": 0, "EAmount": {"Value": 60, "Multiplier": 0, "Unit": "Wh"}, "EVMaxVoltage": {"Value": 400, "Multiplier": 0, "Unit": "V"}, "EVMaxCurrent": {"Value": 32000, "Multiplier": -3, "Unit": "A"}, "EVMinCurrent": {"Value": 10, "Multiplier": 0, "Unit": "A"}}}}}}

I note that the construction of the charge parameter discovery request/response also has some SA schedule creation
        sa_schedule_list = await self.comm_session.evse_controller.get_sa_schedule_list(
            ev_data_context,
            self.comm_session.config.free_charging_service,
            max_schedule_entries,
            departure_time,
        )

But the current  message doesn't seem to use that so we will ignore for simplicity

Taking some time to set up the Node-RED UI, I think that's the best place to start (knowing what signals we can / will send will help define the message behavior, and so on as the call graph grows).  Some initial notes on the UI nodes available:

UI Node Choices

We can't use the date node, as it only gives us per-day granularity
departureTime is defined as a 32-bit unsigned integer, that represents an offset in seconds from the point of time the message is sent.  As much as I'd like to have a fancy UI (pick the time, and it handles it for you), let's hack together a solution that uses that input.

The text node does have a time picker option.  In the interest of time, I won't be using this: just wanted to note that this is an avenue for improvement!

The integer node is not a viable option, for two reasons:

We cannot set the max of 32u
Even if we could, it would be so slow to use the click widget to implement charging 1 second at a time.

For these reasons, I think the best course of action is to add a text node, and then interpret the text into an integer.

Here is where we run into our first design quirk.  Per [V2H2-215]...
> If there is no DepartureTime information available, the EVCC shall not include this message in the ChargeParameterDiscoveryReq message
This means we cannot simply have 0 be our base case for the input component (or use some value like -1 as the "null" - this value must be unsigned).

My first thought was to add a toggle node: something like "enable DepartureTime".  Stepping back, I think this is needlessly complicated, and shouldn't be necessary for the reason below.
When initialized, the text node does not contain any text.  As such, I think we can pass this null value along, and that absence can be used later when we form the ChargeParameterDiscoveryReq.

Without piping through any of the messages, below is a mock up of the module

 UI Screenshots

(I believe we won't need a default injection, we actually want the value to be null)

When sketching up these values, I'm left one concern.  As sketched up, the proposed "setDepartureTime" command will send every time the number is set.  How can we make sure that we only change the DepartureTime value when starting or resuming a charging session?  Will have to spend more time with JsEVManager to figure out how this will look in practice.

Still getting used to the Node-RED workflow, setting up the message flow -- writing these notes down mostly for my own understanding...

As I understand it, the Buffer sim commands function node takes the inputs from each of the input nodes, and adjusts the payload according to the topic.

Screenshot of nodes, example code

if (msg.topic.indexOf('sim_commands') > -1) {
    const s = msg.payload.split('#');
    flow.set('sim_commands_start', s[0]);
// the code continues...

After some searching, it seems the sim_commands topic is defined within the injection of the CarSimulation node, but I cannot find the flows for sim_commands_pause, etc... Am I misunderstanding how the flow get command works?  Where are these being defined?
This leads me to the question: do I even need to filter through the buffer??  For example, the values set by the MaxCurrentSlider aren't being filtered.  I'm going to just assume we don't have to filter it for now, I think that should be OK...

Aha! It looks like the pyjosev library is in two locations
# find / -name states.py
/ext/cache/cpm/josev/dd7dc8e95662d54aca01374e5283ead8d4793261/Josev/iso15118/shared/states.py
/ext/source/build/dist/libexec/everest/3rd_party/josev/iso15118/shared/states.py

I have been editing the one in build/dist, but it may be that the code is getting pulled from the cache. Not sure how the original patch ever worked; maybe some parts are pulled from each location?!
Trying to modify an existing log to see which one is loaded (modifying the one in states.py)
2024-07-16 19:24:00.442684 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: IN BUILD_DIST: Entered state ServiceDiscovery
2024-07-16 19:24:01.223707 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: IN BUILD_DIST: Entered state PaymentServiceSelection
2024-07-16 19:24:01.952899 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: IN BUILD_DIST: Entered state PaymentDetails
2024-07-16 19:24:02.769054 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: IN BUILD_DIST: Entered state Authorization
2024-07-16 19:24:03.475439 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: IN BUILD_DIST: Entered state ChargeParameterDiscovery

Let's make sure that the loggers are set up in the same way...

I might have made changes in the SECC implementation of pyjosev, which is unused in EVerest.
The actual values are here:
https://github.com/EVerest/ext-switchev-iso15118/blob/7f16c4b2c1307ce73798215f34b8fe06862bbae1/iso15118/evcc/controller/simulator.py#L276C15-L276C35

So it is fairly clear that the current ISO 15118-2 implementation does not work the way we had hoped in
https://github.com/EVerest/everest-demo/issues/64#issue-2409427125
Concretely, the EVSE does not send a list of SASchedules; it only sends a single SASchedule that corresponds to the current limits. When the EVSE sent the ChargeParameterDiscoveryRes, it basically said that you can get 6900 W for the rest of the day. This is technically correct because we started with the lowest current, but I don't think it will give us the energy we requested.
To run some numbers:

we requested 60x10^3 Wh = 60,000 Wh with a departure time of 21600 (6 hours)
the max current was limited to 10A, 3 phase. So the max power is 240 * 10 = 2400 W. For some reason, the max power is actually set to 6900W (not sure why, need to investigate)
and then the SASchedule is returned in watts 6,900W for the entire day.

That gives us 165,600 Wh, but doesn't let us leave after 6 hours
if we do try to leave after 6 hours, we will end up with only 41,400 Wh which is less than what we requested

So basically, departure time does not work, and we only send a single SA Schedule as I had speculated from the code earlier. Not sure if it is super easy to fix this, but I have the afternoon to try!

Parsing the syntax & design behind the MQTT routes...  My current understanding is that the DepartureTime should be send via the /carsim/cmd/{} route, as the DepartureTime is set by the EVCC (read: vehicle).
When looking at the docs for these routes (The (EVManager), we can see that there are several commands that are sent within a execute_charging_session or modify_charging_session message.  As such, it doesn't seem appropriate to create an entirely new route; rather, I think the goal is to add a separate command within the execute_charging_session packet.  This goes back to my explorations earlier -- turns out I should be adding to the sim commands.  I'm still a bit confused as to this process, but will do some digging into JsEvManager and EvManager's car_simulatorImpl.cpp.  Should also probably take some time to investigate the testing code that covers these functions...

First, where is the limit computation coming from?
It is
int SmartChargingHandler::get_power_limit(const int limit, const int nr_phases,
                                          const ChargingRateUnitEnum& unit_of_limit) {
    if (unit_of_limit == ChargingRateUnitEnum::W) {
        return limit;
    } else {
        return limit * LOW_VOLTAGE * nr_phases;
    }
}

ah
const int LOW_VOLTAGE = 230;

updating the power limits in https://github.com/EVerest/everest-demo/issues/64#issuecomment-2231736589

we requested 60x10^3 Wh = 60,000 Wh with a departure time of 21600 (6 hours)

the max current was limited to 10A, 3 phase. So the max power is 230 (LOW_VOLTAGE) * 10 * 3 = 6900 W.
Then the SASchedule is returned in watts @ 6,900W for the entire day.

That gives us 165,600 Wh (6900 * 24) which is more than the energy we want , but doesn't let us leave after 6 hours
if we do try to leave after 6 hours, we will end up with only 41,400 Wh (6900 * 6) which is less than what we requested

Next question: why are we not handling the departure time correctly, and why are we returning exactly one SASchedule?

Confirmed that the return SASchedules (EVSE -> car) are created in the modules/EvseV2G/iso_server.cpp, in handle_iso_charge_parameter_discovery. We create one SASchedule with one PMax entry, and we set it to the entire day.
            conn->ctx->evse_v2g_data.evse_sa_schedule_list.SAScheduleTuple.array[0]
                .PMaxSchedule.PMaxScheduleEntry.array[0]
                .RelativeTimeInterval.start = 0;
            conn->ctx->evse_v2g_data.evse_sa_schedule_list.SAScheduleTuple.array[0]
                .PMaxSchedule.PMaxScheduleEntry.array[0]
                .RelativeTimeInterval.duration_isUsed = 1;
            conn->ctx->evse_v2g_data.evse_sa_schedule_list.SAScheduleTuple.array[0]
                .PMaxSchedule.PMaxScheduleEntry.array[0]
                .RelativeTimeInterval.duration = SA_SCHEDULE_DURATION;
            conn->ctx->evse_v2g_data.evse_sa_schedule_list.SAScheduleTuple.array[0]
                .PMaxSchedule.PMaxScheduleEntry.arrayLen = 1;
            conn->ctx->evse_v2g_data.evse_sa_schedule_list.SAScheduleTuple.arrayLen = 1;

So achieving our original goals, with multiple SASchedules is going to be fairly complex. Given the short timeframe, let us at least try for a much simpler option in with there is a single charging profile set, but the user specifies a departure time and energy need, and we spread the energy out over the entire charging period.

Starting to build a proper dev plan!
It seems that once you add a command to /carsim/cmd/{}, it needs to be registered in both JsEvManager and EVManager's car_simulatorImpl.cpp.
So, we need to finally answer the question: How do we add commands to the message?
Looking at the Buffer sim commands function node's code:
if (msg.topic.indexOf('sim_commands') > -1) {
    const s = msg.payload.split('#');
    flow.set('sim_commands_start', s[0]);
    flow.set('sim_commands_stop', s[1]);
    flow.set('sim_commands_pause', s[2]);
    flow.set('sim_commands_resume', s[3]);
}
// Code continues...

We can use the default injection to understand exactly how the payload is generated.  The following string...
sleep 1;iec_wait_pwr_ready;sleep 1;draw_power_regulated 16,3;sleep 36000#unplug#pause;sleep 3600#draw_power_regulated 16,3;sleep 36000

Assigns itself to each of the sim commands, as follows...

Flow Variable (Command)
Flow Value (Commands)

Start
sleep 1;iec_wait_pwr_ready;sleep 1;draw_power_regulated 16,3;sleep 36000

Stop
unplug

Pause
pause;sleep 3600

Resume
draw_power_regulated 16,3;sleep 36000

Ah, that makes more sense -- we set a series of commands for each possible method of interacting with the simulation loop!  Cool.  Know this, we finally have some steps to move forward:

[ ] The Set DepartureTime node should add a new command set_departure_time to the Start and Resume phases of the simulation.

[ ] I believe this can be done within the Buffer sim commands function, though we may want to separate out the functionality to a second function node.  TBD.
Aside: I think we don't have to worry about the type of the input for this command on the Node-RED side of things.  Everything is already being input as a string, so we can parse / throw errors after the package has been received.

[ ] Once we've written the code to send these messages, the command must be registered with both of the managers described above (JsEvManager, EVManager).
[ ] Once registered, we can define and detail the implementation!

Ok, so I can confirm that I can read the values correctly in the ISO server code,
2024-07-16 23:30:07.580610 [WARN] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: max_current 32.000000, nom_voltage 230, pmax 22080
2024-07-16 23:30:07.580705 [WARN] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: Requested departure time 0, requested energy 60.000000

now to actually use the departure time and requested energy...

First design hiccup: We cannot simply pipe the set_departure_time command into the messages like the other commands.  Consider the following scenario:

User selects CarSimulation AC ISO 15118-2

Result: All 4 commands are set from this "default sim profile"

User then inputs a departure time

Result: command is propagated to the commands

User then changes their mind, and selects AC ISO 15118-2: Plug & Charge

Result: All 4 commands are set, overwriting the departure time insertion.  The DepartureTime will not be propagated again until it is mutated

Solution: We still need have the set_departure_time send its message through the buffer, but we should also set a flag somewhere that the other that the car simulation node can check.  I think this will be done via a "Flow Variable", as we have done is done with the sim_commands.  Once I figure out how to set one of these scoped variables, this should be a relatively fix

So I am not quite sure how we go from a complex set of schedule periods to a single limit.
OCPP calls OCPP201::set_external_limits which passes in a composite schedule.
But when we get to the energy manager, we only return one optimized schedule
2024-07-16 23:59:55.150578 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-16 23:59:55.150671 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-16 23:59:55.150816 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W
2024-07-16 23:59:55.277531 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000

If I can figure out how to pass this through, we might be able to do a better demo.
Also checking to see whether the schedules are automatically recalculated (there is a timer that sets the limits)

None of them are valid
2024-07-16 23:56:11.012269 [WARN] ocpp:OCPP201    module::OCPP201::ready()::<lambda()> :: Received a new Charging Schedules from the CSMS or another actor.
2024-07-16 23:56:11.012377 [INFO] ocpp:OCPP201     :: ProfileId #1 Kind: Absolute
2024-07-16 23:56:11.012454 [INFO] ocpp:OCPP201     :: #1 find_period_at> 2024-07-17T00:00:00.000Z
2024-07-16 23:56:11.012531 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T23:56:11.012Z
2024-07-16 23:56:11.012617 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-17T00:00:00.000Z
2024-07-16 23:56:11.012693 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-17T01:00:00.000Z
2024-07-16 23:56:11.012797 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T23:56:11.012Z
2024-07-16 23:56:11.012897 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-17T01:00:00.000Z
2024-07-16 23:56:11.012973 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-17T02:00:00.000Z
2024-07-16 23:56:11.013047 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T23:56:11.012Z
2024-07-16 23:56:11.013118 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-17T02:00:00.000Z
2024-07-16 23:56:11.013267 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-18T00:00:00.000Z
2024-07-16 23:56:11.013349 [INFO] ocpp:OCPP201     :: PeriodDateTimePair>  end_time: 2080-03-01T16:33:27.779Z
2024-07-16 23:56:11.013443 [INFO] ocpp:OCPP201     :: ProfileId #1 Kind: Absolute
2024-07-16 23:56:11.013473 [INFO] ocpp:OCPP201     :: #1 find_period_at> 2024-07-17T00:00:00.000Z
2024-07-16 23:56:11.013502 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T23:56:11.013Z
2024-07-16 23:56:11.013529 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-17T00:00:00.000Z
2024-07-16 23:56:11.013612 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-17T01:00:00.000Z
2024-07-16 23:56:11.013721 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T23:56:11.013Z
2024-07-16 23:56:11.013799 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-17T01:00:00.000Z
2024-07-16 23:56:11.013839 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-17T02:00:00.000Z
2024-07-16 23:56:11.013986 [INFO] ocpp:OCPP201     ::    find_period_at>        start_time> 2024-07-16T23:56:11.013Z
2024-07-16 23:56:11.014055 [INFO] ocpp:OCPP201     ::    find_period_at> period_start_time> 2024-07-17T02:00:00.000Z
2024-07-16 23:56:11.014151 [INFO] ocpp:OCPP201     ::    find_period_at>   period_end_time> 2024-07-18T00:00:00.000Z
2024-07-16 23:56:11.014379 [INFO] ocpp:OCPP201     :: PeriodDateTimePair>  end_time: 2080-03-01T16:33:27.779Z
2024-07-16 23:56:11.098733 [ERRO] ocpp:OCPP201    void ocpp::v201::ChargePoint::handle_set_charging_profile_req(ocpp::Call<ocpp::v201::SetChargingProfileRequest>) :: Received profile validity: Validsetting response to {
    "status": "Accepted"
}
2024-07-16 23:56:11.329473 [INFO] energy_manager:  ::                                NO TRADE
2024-07-16 23:56:11.329732 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}

Switched over, but the timer doesn't seem to be recalculating
2024-07-16 23:59:59.613293 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-16 23:59:59.613351 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-16 23:59:59.701427 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:00.012011 [ERRO] ocpp:OCPP201    void ocpp::v201::ChargePoint::handle_message(const ocpp::EnhancedMessage<ocpp::v201::MessageType>&) :: Handle_message called: [3,"6459f8b8-bc74-4cf0-a946-20f0007d2338",{}]
2024-07-17 00:00:00.012105 [ERRO] ocpp:OCPP201    void ocpp::v201::ChargePoint::handle_message(const ocpp::EnhancedMessage<ocpp::v201::MessageType>&) :: json_message called: [3,"6459f8b8-bc74-4cf0-a946-20f0007d2338",{}]
2024-07-17 00:00:00.792140 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:00.792267 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:00.792492 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:00.792576 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:00.881991 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:01.929852 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:01.930111 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:01.930357 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:01.930521 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:01.977783 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:03.024977 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:03.025242 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:03.025353 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:03.025468 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:03.073103 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:04.119963 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:04.120263 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:04.120372 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:04.120509 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:04.208647 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:05.297367 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:05.297640 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:05.297807 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:05.297898 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:05.386170 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:06.434387 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:06.434612 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:06.434808 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:06.434921 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:06.523742 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:07.570195 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:07.570478 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:07.570590 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:07.570651 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:07.618045 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:08.663480 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:08.663657 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:08.663806 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:08.663845 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:08.752327 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:09.839791 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:09.840045 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:09.840189 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:09.840265 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:09.888312 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:10.975204 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:10.975472 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:10.975792 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:10.975854 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:10.982449 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:12.028872 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:12.029073 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:12.029182 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:12.029243 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:12.075557 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:13.162296 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:13.162551 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:13.162727 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:13.162803 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:13.210296 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:14.259348 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:14.259736 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:14.259860 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:14.259930 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:14.307981 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:15.316521 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:15.316672 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:15.316752 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:15.316797 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:15.429489 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:16.476905 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:16.477109 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:16.477219 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:16.477280 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:16.564772 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:17.611086 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:17.611292 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:17.611411 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:17.611671 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:17.659640 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:18.708795 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:18.708973 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:18.709107 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:18.709204 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:18.755105 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:19.803908 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:19.804180 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:19.804335 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:19.804417 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:19.852383 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:20.901811 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:20.902077 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:20.902219 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:20.902298 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:20.950124 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:21.998977 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:21.999181 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:21.999287 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:21.999345 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:22.005213 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:23.053485 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:23.053674 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:23.053760 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:23.053805 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:23.140427 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:24.189693 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:24.189949 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:24.190099 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:24.190178 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:24.197073 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:25.285275 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:25.285501 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:25.285684 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:25.285745 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:25.333425 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:26.421466 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:26.421780 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:26.421897 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:26.421958 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:26.459672 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:27.508468 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:27.508760 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:27.508947 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:27.509105 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:27.557371 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:28.604746 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:28.604951 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:28.605049 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:28.605155 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:28.652187 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:29.741137 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:29.741400 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:29.741673 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:29.741871 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:29.830648 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:30.876287 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:30.876542 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:30.876706 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:30.876767 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:30.882841 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:31.928334 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:31.928511 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:31.928593 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:31.928635 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:32.014657 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:33.061162 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:33.061422 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:33.061626 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:33.061730 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:33.109183 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:34.200705 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:34.200998 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:34.201159 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:34.201341 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:34.208331 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:35.254159 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:35.254723 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:35.254863 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:35.255011 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:35.311777 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:36.336359 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:36.336616 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:36.336756 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:36.336835 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:36.343761 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:37.391450 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:37.391636 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:37.391733 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:37.391787 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:37.397841 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:38.485356 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:38.485579 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:38.485676 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:38.485839 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:38.532511 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:39.620220 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:39.620662 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:39.620795 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:39.620870 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:39.626831 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:40.673955 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:40.674196 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:40.674377 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:40.674611 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:40.721364 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:41.811856 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:41.812144 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:41.812277 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:41.812338 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:41.901316 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:42.989366 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:42.989549 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:42.989683 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:42.989739 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:43.037266 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:44.125913 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:44.126223 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:44.126531 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:44.126617 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:44.173596 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:45.219017 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:45.219339 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:45.219520 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:45.219652 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:45.306465 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:46.355596 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:46.355803 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:46.355912 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:46.355973 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:46.403151 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:47.449671 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:47.449877 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:47.449985 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:47.450046 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:47.456590 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:48.548042 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:48.548305 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:48.548422 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:48.548484 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:48.596305 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:49.642440 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:49.642696 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:49.642835 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:49.642914 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:49.690390 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:50.737078 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:50.737253 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:50.737339 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:50.737409 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:50.782754 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:51.829982 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:51.830249 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:51.830452 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:51.830515 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:51.877462 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:52.924249 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:52.924422 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:52.924520 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:52.924571 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:52.970958 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:54.019200 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:54.019504 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:54.019645 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:54.019723 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:54.068059 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:55.117471 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:55.117729 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:55.117869 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:55.117946 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:55.166134 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:56.253945 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:56.254246 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:56.254446 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:56.254576 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:56.344033 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:57.433494 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:57.433754 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:57.433894 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:57.434032 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:57.482176 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:58.530312 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:58.530578 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:58.530750 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:58.530829 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:58.562756 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:00:59.611335 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:00:59.611658 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:00:59.611842 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:00:59.611931 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:00:59.660272 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:01:00.707389 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:01:00.707572 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}
2024-07-17 00:01:00.707675 [INFO] energy_manager:  :: returning optimized values vector of length 1
2024-07-17 00:01:00.707727 [INFO] energy_manager:  :: evse_manager_1 Enforce limits 32A -9999W

2024-07-17 00:01:00.796434 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: In ISO15118 charger impl, after updating AC max current to 32.000000, we get 32.000000
2024-07-17 00:01:01.842880 [INFO] energy_manager:  ::                                NO TRADE
2024-07-17 00:01:01.843087 [INFO] energy_manager:  :: Sending enfored limits (import) to :evse_manager_1 {
    "ac_max_current_A": 32.0
}

Yay! with some fairly obvious changes, this now works!
2024-07-17 00:41:59.842439 [WARN] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: before adjusting for departure time, max_current 32.000000, nom_voltage 230, pmax 22080

2024-07-17 00:41:59.842500 [WARN] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: Requested departure time 21600, requested energy 60000.000000

2024-07-17 00:41:59.842541 [WARN] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: Min hours to charge 2.717391, requested departure time in hours 6.000000, plenty of time to charge, lowering pmax = 1.000000

2024-07-17 00:41:59.843014 [ERRO] iso15118_charge void dlog_func(dloglevel_t, const char*, int, const char*, const char*, ...) :: CHECKME: when is this called and do we need to modify it as well
2024-07-17 00:41:59.925920 [INFO] evse_manager_1:  ::                                     CAR ISO V2G ChargeParameterDiscoveryReq
2024-07-17 00:41:59.981000 [INFO] evse_manager_1:  :: EVSE ISO V2G ChargeParameterDiscoveryRes
2024-07-17 00:41:59.990256 [DEBG] iso15118_car    pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Decoded message (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message":{"Header":{"SessionID":"3968BF77DD9EBDB9"},"Body":{"ChargeParameterDiscoveryRes":{"ResponseCode":"OK","EVSEProcessing":"Finished","SAScheduleList":{"SAScheduleTuple":[{"SAScheduleTupleID":1,"PMaxSchedule":{"PMaxScheduleEntry":[{"RelativeTimeInterval":{"start":0,"duration":21600},"PMax":{"Multiplier":0,"Unit":"W","Value":10000}}]}}]},"AC_EVSEChargeParameter":{"AC_EVSEStatus":{"NotificationMaxDelay":0,"EVSENotification":"None","RCD":false},"EVSENominalVoltage":{"Multiplier":-1,"Unit":"V","Value":2300},"EVSEMaxCurrent":{"Multiplier":-1,"Unit":"A","Value":320}}}}}}

However, the EVSEMaxCurrent needs to be fixed, in the second part of the handler. Not quite sure why we are handling it twice, but whatever...

Hm, more hiccups -- it doesn't seem to be as simple as "slotting in a new command", I think I'm missing some key aspect of Node-RED.  When adding the command with the following code...
function handleDepartureTime() {
    const cmd = flow.get('sim_departure_time');
    let start = flow.get('sim_commands_start').split(';');
    let resume = flow.get('sim_commands_resume').split(';');
    start.splice(3, 1, cmd);
    resume.splice(3, 1, cmd);
    flow.set('sim_comands_start', start.join())
    flow.set('sim_commands_resume', resume.join())
}
if (msg.topic.indexOf('sim_commands') > -1) {
    const s = msg.payload.split('#');
    flow.set('sim_commands_start', s[0]);
    flow.set('sim_commands_stop', s[1]);
    flow.set('sim_commands_pause', s[2]);
    flow.set('sim_commands_resume', s[3]);
    handleDepartureTime();
} else if (msg.topic == 'departure_time') {
    cmd = 'iso_set_departure_time ' + msg.payload
    flow.set('sim_departure_time', cmd);
    handleDepartureTimeUpdate();
} else if (msg.payload == 'start') {
// Code Continues...

And updating the charging profiles accordingly, it appears that the flow contexts are not being properly set:

What gives?  Clearly I'm missing something -- the ",ac" is being interpreted into a full string, so there's something going on under the hood that I'm missing...

Reading the docs of nodered, I was assuming the addition of a context should be as simple as .set().  It seems there is some initialization step that I've missed, as all 4 contexts are populated upon a fresh deployment.  This doesn't seem to occur within the initialize Connector nodes -- I guess I need to do more reading...

Well, that's an embarrassing typo to miss -- it helps if you spell your context variable names correctly 🤦  Issue seems to be that I misspelled the start command.  Making some tweaks now, will update accordingly.

Woohoo!! The UI is finally tee'ing up the commands properly.  Below is a video of the functionality, and the JSON file of the flow diagram.
https://github.com/user-attachments/assets/6f67939e-2040-4fcb-b03c-e980fc8b5966
Uploading flow_with_departureTimes.json…

Great! Now I think you just need to set it in the connection context (similar to the payment mode) and then populate the departure time in PyJosev from that instead of hardcoding it to 0 in build/dist/libexec/everest/3rd_party/josev/iso15118/evcc/controller/simulator.py line 302.

I am fully done with my changes, and they appear to work. We cannot demo what we had originally planned to demo, but we can demo something interesting with departure times. I'm going to edit the main description here (https://github.com/EVerest/everest-demo/issues/64#issue-2409427125) to outline our plans for the this demo and create a follow-up issue for the more complex demo in the future.

Alright!  Time to start setting the commands in context.  Since we snuck the command into the start and resume commands sequences, we luckily don't have to edit any of the mqtt routes.  So, let's start (somewhat arbitrarily) with JsEvManager.
First things first, I think we can ignore the corresponding mainfest.yaml file, as nothing here pertains to the departureTime changes.  Then, we need to look at the index.js.  Within this file, it appears there's a few functions we'll need to edit:

[ ] simdata_reset_defaults()

I think this is where we can set the mod variable's parameter that contains the 32u (default null, to reflect the lack of extension).  Likewise, the registerAllCommands() function should be mutating whatever variable we set here, correct...?  For now, let's call this value mod.iso_departure_time.

[ ] registerAllCommands()