EV řízení: zápis Amps-to-use přes journal + watchdog + okamžitý replan po příjezdu
Some checks failed
CI and deploy / migration-check (push) Successful in 39s
CI and deploy / deploy (push) Failing after 9m55s

Bod 1 — write_ev_setpoints reálně (konec TODO stubu):
- reg 15 (0=stop, 6–32 A) z plánu přes _current_limit_for_charger; plná
  journal pipeline (create_modbus_commands → execute, verify job 2 min generic)
- watchdog reg 19=300 s + reg 20=8 A: výpadek EMS → wallbox po 5 min failsafe
  8 A (auto se přes noc nabije); drop-unchanged → zapisuje se jen při změně
- fn_modbus_last_verified_map: + p_asset_type (drop 2-arg; dosud hardcoded
  'inverter' — pro chargery vracela {})
- verify: SELF_SUSTAIN fallback explicitně jen pro asset_type='inverter' —
  mismatch wallboxu nesmí degradovat režim celé site
- journal register_name: mimo inverter platí jméno od volajícího

Bod 2 — telemetry_collector: přechod available→connected spustí fire-and-forget
run_rolling_replan(triggered_by=ev_arrival:<code>) + export_setpoints přes BG
pool — reakce na příjezd ~60 s místo až 15 min.

Bod 3 (Tesla API SoC) čeká na developer credentials.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dusan Vojacek
2026-06-11 22:51:38 +02:00
parent e7b87fbabd
commit 0ed6f18e1a
5 changed files with 148 additions and 12 deletions

View File

@@ -46,8 +46,12 @@ async def _fetch_written_deye_clock_commands(
return list(rows)
async def _fetch_last_verified_inverter_registers(
site_id: int, inverter_asset_id: int, db: asyncpg.Connection
async def _fetch_last_verified_registers(
site_id: int,
asset_id: int,
db: asyncpg.Connection,
*,
asset_type: str = "inverter",
) -> dict[int, int]:
"""
Poslední hodnota na zařízení podle journalu (jen status verified).
@@ -55,15 +59,25 @@ async def _fetch_last_verified_inverter_registers(
"""
raw = await db.fetchval(
"""
select ems.fn_modbus_last_verified_map($1::int, $2::int)
select ems.fn_modbus_last_verified_map($1::int, $2::int, $3::text)
""",
site_id,
inverter_asset_id,
asset_id,
asset_type,
)
data = raw if isinstance(raw, dict) else json.loads(raw)
return {int(k): int(v) for k, v in data.items()}
async def _fetch_last_verified_inverter_registers(
site_id: int, inverter_asset_id: int, db: asyncpg.Connection
) -> dict[int, int]:
"""Zpětně kompatibilní alias (Deye cesty)."""
return await _fetch_last_verified_registers(
site_id, inverter_asset_id, db, asset_type="inverter"
)
def _drop_registers_matching_last_verified(
registers: list[tuple[int, str, int]],
last_verified: dict[int, int],
@@ -102,8 +116,14 @@ async def create_modbus_commands(
Vrátí list command IDs.
"""
ids: list[int] = []
for reg, _ignored_name, val in registers:
register_name = DEYE_REGISTER_NAMES.get(reg, f"reg_{reg}")
for reg, given_name, val in registers:
# Deye registry mají kanonická jména; pro ostatní zařízení (Teltonika…)
# platí jméno dodané volajícím.
register_name = (
DEYE_REGISTER_NAMES.get(reg)
if asset_type == "inverter"
else None
) or given_name or f"reg_{reg}"
cmd_id = await db.fetchval(
"""
INSERT INTO ems.modbus_command