EV arrival hold: po detekci píchnutí okamžitě 0 A — nabíjení spouští až plán
TeltoCharge po připojení kabelu sám rozjede nabíjení svým defaultem; EMS ho dosud dohnal až exportem setpointů (do 15 min). _on_ev_arrival nyní před replanem zapíše přes journal telto_amps_to_use=0 (write_ev_arrival_hold), replan+export vzápětí nastaví plánované ampéry. Watchdog (300 s → failsafe 8 A) zachován — výpadek EMS auto nenechá na 0 A. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -128,6 +128,56 @@ async def write_ev_setpoints(
|
|||||||
return f"OK EV: {written}/{len(rows)} charger(s) written"
|
return f"OK EV: {written}/{len(rows)} charger(s) written"
|
||||||
|
|
||||||
|
|
||||||
|
async def write_ev_arrival_hold(
|
||||||
|
site_id: int, charger_code: str, db: asyncpg.Connection
|
||||||
|
) -> bool:
|
||||||
|
"""Okamžitě po DETEKCI příjezdu zapsat 0 A na daný wallbox (přes journal).
|
||||||
|
|
||||||
|
TeltoCharge po připojení kabelu sám rozjede nabíjení svým defaultem —
|
||||||
|
nabíjet smí až PLÁN (replan + export běží hned poté v _on_ev_arrival,
|
||||||
|
takže držení trvá sekundy až ~1 min). Watchdog registry se zapíší spolu
|
||||||
|
s 0 A (drop-unchanged je po prvním verified stejně přeskočí).
|
||||||
|
"""
|
||||||
|
from services.control.modbus_journal import (
|
||||||
|
create_modbus_commands,
|
||||||
|
execute_modbus_commands,
|
||||||
|
)
|
||||||
|
|
||||||
|
row = await db.fetchrow(
|
||||||
|
"""
|
||||||
|
SELECT ec.id AS asset_id, ec.code, se.host, se.port, se.unit_id
|
||||||
|
FROM ems.asset_ev_charger ec
|
||||||
|
JOIN ems.site_endpoint se ON se.id = ec.endpoint_id
|
||||||
|
WHERE ec.site_id = $1
|
||||||
|
AND ec.code = $2
|
||||||
|
AND ec.schedulable = true
|
||||||
|
AND se.enabled = true
|
||||||
|
AND se.endpoint_type = 'modbus_tcp'
|
||||||
|
""",
|
||||||
|
site_id,
|
||||||
|
charger_code,
|
||||||
|
)
|
||||||
|
if row is None:
|
||||||
|
return False
|
||||||
|
cmd_ids = await create_modbus_commands(
|
||||||
|
site_id,
|
||||||
|
None,
|
||||||
|
"ev_charger",
|
||||||
|
int(row["asset_id"]),
|
||||||
|
str(row["code"]),
|
||||||
|
str(row["host"]),
|
||||||
|
int(row["port"] or 502),
|
||||||
|
int(row["unit_id"] if row["unit_id"] is not None else 1),
|
||||||
|
_telto_setpoint_registers(0),
|
||||||
|
db,
|
||||||
|
)
|
||||||
|
ok = await execute_modbus_commands(cmd_ids, db)
|
||||||
|
logger.info(
|
||||||
|
"EV arrival hold [%s]: 0 A %s", charger_code, "written" if ok else "FAILED"
|
||||||
|
)
|
||||||
|
return bool(ok)
|
||||||
|
|
||||||
|
|
||||||
async def write_heat_pump_setpoint(
|
async def write_heat_pump_setpoint(
|
||||||
site_id: int, setpoints: ControlSetpoints, db: asyncpg.Connection
|
site_id: int, setpoints: ControlSetpoints, db: asyncpg.Connection
|
||||||
) -> str:
|
) -> str:
|
||||||
|
|||||||
@@ -87,6 +87,17 @@ async def _on_ev_arrival(site_id: int, charger_code: str) -> None:
|
|||||||
from services.planning_engine import run_rolling_replan
|
from services.planning_engine import run_rolling_replan
|
||||||
|
|
||||||
async with _BG_POOL.acquire() as conn:
|
async with _BG_POOL.acquire() as conn:
|
||||||
|
# Wallbox po píchnutí sám rozjíždí nabíjení svým defaultem — držet
|
||||||
|
# 0 A, dokud nerozhodne plán (export běží hned po replanu níže).
|
||||||
|
try:
|
||||||
|
from services.control.outputs import write_ev_arrival_hold
|
||||||
|
|
||||||
|
await write_ev_arrival_hold(site_id, charger_code, conn)
|
||||||
|
except Exception:
|
||||||
|
logger.exception(
|
||||||
|
"EV arrival hold failed (site=%s, %s) — WB pojede defaultem do exportu",
|
||||||
|
site_id, charger_code,
|
||||||
|
)
|
||||||
# Tesla: skutečné SoC do session PŘED replanem (selhání nesmí blokovat plán)
|
# Tesla: skutečné SoC do session PŘED replanem (selhání nesmí blokovat plán)
|
||||||
try:
|
try:
|
||||||
await _patch_session_from_tesla(site_id, charger_code, conn)
|
await _patch_session_from_tesla(site_id, charger_code, conn)
|
||||||
|
|||||||
Reference in New Issue
Block a user