Skip to content

Commit

Permalink
Feat/add way to delay ev request (#441)
Browse files Browse the repository at this point in the history
* added a way to delay the EVCC Charging Loop Req

* added a way to delay the EV power request
  • Loading branch information
tropxy authored Feb 5, 2025
1 parent 79f5c4f commit 81896a0
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 48 deletions.
16 changes: 16 additions & 0 deletions iso15118/evcc/controller/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,22 @@ class EVControllerInterface(ABC):
# ============================================================================
# | COMMON FUNCTIONS (FOR ALL ENERGY TRANSFER MODES) |
# ============================================================================
@abstractmethod
async def charge_loop_delay(self) -> int:
"""
Delays the charging loop for a certain amount of time. This could be used
for example to simulate a delay in the charging process, e.g. due to a
temporary lack of power.
Returns:
The amount of time the charging loop was delayed in seconds
Relevant for:
- DIN SPEC 70121
- ISO 15118-2
- ISO 15118-20
"""
raise NotImplementedError

@abstractmethod
async def get_evcc_id(self, protocol: Protocol, iface: str) -> str:
Expand Down
11 changes: 6 additions & 5 deletions iso15118/evcc/controller/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class SimEVController(EVControllerInterface):
def __init__(self, evcc_config: EVCCConfig):
self.config = evcc_config
self.charging_loop_cycles: int = max(evcc_config.charge_loop_cycle, 1)
self.charge_loop_delay_time: int = min(evcc_config.charge_loop_delay_time, 50)
self.increment = (1 / self.charging_loop_cycles) * 100
self.precharge_loop_cycles: int = 0
self.welding_detection_cycles: int = 0
Expand Down Expand Up @@ -531,6 +532,10 @@ async def process_sa_schedules_v2(
ChargingProfile(profile_entries=evcc_profile_entry_list),
)

async def charge_loop_delay(self) -> int:
"""Overrides EVControllerInterface.delay_charge_loop()."""
return self.charge_loop_delay_time

async def continue_charging(self) -> bool:
"""Overrides EVControllerInterface.continue_charging()."""
if self.charging_loop_cycles == 0 or await self.is_charging_complete():
Expand Down Expand Up @@ -574,11 +579,7 @@ async def is_precharged(
async def get_dc_ev_power_delivery_parameter_dinspec(
self,
) -> DCEVPowerDeliveryParameterDINSPEC:
return DCEVPowerDeliveryParameterDINSPEC(
dc_ev_status=await self.get_dc_ev_status_dinspec(),
bulk_charging_complete=False,
charging_complete=await self.continue_charging(),
)
pass

async def get_dc_ev_power_delivery_parameter(self) -> DCEVPowerDeliveryParameter:
return DCEVPowerDeliveryParameter(
Expand Down
2 changes: 2 additions & 0 deletions iso15118/evcc/evcc_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class EVCCConfig(BaseModel):

# charge cycle count
charge_loop_cycle: Optional[int] = Field(10, alias="chargeLoopCycle")
# charge loop cycle delay before next cycle
charge_loop_delay_time: Optional[int] = Field(5, alias="chargeLoopDelay")

def load_raw_values(self):
# conversion of list of strings to enum types.
Expand Down
9 changes: 9 additions & 0 deletions iso15118/evcc/states/din_spec_states.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
SessionStopRes.
"""

import asyncio
import logging
from time import time
from typing import Any, List, Union
Expand Down Expand Up @@ -713,6 +714,14 @@ async def process_message(
logger.debug("EVSE Notification received requesting to stop charging.")
await self.stop_charging()
elif await self.comm_session.ev_controller.continue_charging():
try:
delay: int = (
await self.comm_session.ev_controller.charge_loop_delay()
) # noqa
logger.info(f"Next ChargeLoop Req in {delay} seconds")
await asyncio.sleep(delay)
except Exception as e:
logger.info(f"No delay for the next ChargeLoop Req. Reason {e}")
self.create_next_message(
None,
await self.build_current_demand_req(),
Expand Down
17 changes: 17 additions & 0 deletions iso15118/evcc/states/iso15118_20_states.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
SessionStopRes.
"""

import asyncio
import logging
import time
from typing import Any, List, Union, cast
Expand Down Expand Up @@ -1286,6 +1287,14 @@ async def process_message(
)

elif await self.comm_session.ev_controller.continue_charging():
try:
delay: int = (
await self.comm_session.ev_controller.charge_loop_delay()
) # noqa
logger.info(f"Next ChargeLoop Req in {delay} seconds")
await asyncio.sleep(delay)
except Exception as e:
logger.info(f"No delay for the next ChargeLoop Req. Reason {e}")
scheduled_params, dynamic_params = None, None
bpt_scheduled_params, bpt_dynamic_params = None, None
selected_energy_service = self.comm_session.selected_energy_service
Expand Down Expand Up @@ -1661,6 +1670,14 @@ async def process_message(
)

elif await self.comm_session.ev_controller.continue_charging():
try:
delay: int = (
await self.comm_session.ev_controller.charge_loop_delay()
) # noqa
logger.info(f"Next ChargeLoop Req in {delay} seconds")
await asyncio.sleep(delay)
except Exception as e:
logger.info(f"No delay for the next ChargeLoop Req. Reason {e}")
current_demand_req = await self.build_current_demand_data()

self.create_next_message(
Expand Down
17 changes: 17 additions & 0 deletions iso15118/evcc/states/iso15118_2_states.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
SessionStopRes.
"""

import asyncio
import logging
from time import time
from typing import Any, List, Union
Expand Down Expand Up @@ -1172,6 +1173,14 @@ async def process_message(
await self.stop_charging()

elif await self.comm_session.ev_controller.continue_charging():
try:
delay: int = (
await self.comm_session.ev_controller.charge_loop_delay()
) # noqa
logger.info(f"Next ChargeLoop Req in {delay} seconds")
await asyncio.sleep(delay)
except Exception as e:
logger.info(f"No delay for the next ChargeLoop Req. Reason {e}")
self.create_next_message(
ChargingStatus,
ChargingStatusReq(),
Expand Down Expand Up @@ -1384,6 +1393,14 @@ async def process_message(
await self.stop_charging()

elif await self.comm_session.ev_controller.continue_charging():
try:
delay: int = (
await self.comm_session.ev_controller.charge_loop_delay()
) # noqa
logger.info(f"Next ChargeLoop Req in {delay} seconds")
await asyncio.sleep(delay)
except Exception as e:
logger.info(f"No delay for the next ChargeLoop Req. Reason {e}")
current_demand_req = await self.build_current_demand_data()

self.create_next_message(
Expand Down
80 changes: 37 additions & 43 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 81896a0

Please sign in to comment.