Režimy: okamžitá exekuce setpointů po ručním přepnutí módu
All checks were successful
CI and deploy / deploy (push) Successful in 41s
CI and deploy / migration-check (push) Successful in 25s

Control exporter běží jen v minutách 14/29/44/59 — po POST /mode střídač
až ~15 min jel podle starého plánu (uživatel: 'SELF_SUSTAIN se jen přestane
řídit'). Defaulty režimů exporter umí správně (SELF_SUSTAIN: 108/109=max A,
export 0; PRESERVE: lock; CHARGE_CHEAP: max nabíjení bez exportu; MANUAL:
bez zápisu) — chyběl jen trigger. Fix: fire-and-forget export_setpoints
hned po fn_set_mode (chyby do logu, API neblokuje Modbus).

Pozn.: systémové přepnutí mismatch→SELF_SUSTAIN dál čeká na 2min verify tick
— případné zrychlení řešit v notification_service (mimo rozsah).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dusan Vojacek
2026-06-11 16:35:25 +02:00
parent c9409b0666
commit e42569f629

View File

@@ -2,6 +2,7 @@
from __future__ import annotations
import asyncio
import logging
import os
from datetime import datetime, timezone
@@ -24,6 +25,7 @@ from app.ws_manager import manager
from fastapi import Depends, FastAPI, HTTPException, Request, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
from services.control_exporter import export_setpoints
from services.notification_service import run_fn_set_mode_with_discord
logger = logging.getLogger(__name__)
@@ -248,6 +250,31 @@ async def set_site_mode(
except Exception as e:
logger.warning("Loxone EMS_Mode notify failed for site %s: %s", site_id, e)
# Okamžitá exekuce nového režimu: control exporter jinak běží jen v minutách
# 14/29/44/59, takže by střídač až ~15 min jel podle starého plánu (např.
# SELF_SUSTAIN má hned nastavit 108/109 na max A a vypnout přetoky).
# Fire-and-forget — API neblokuje Modbus zápisy; chyby jen do logu.
asyncio.create_task(_export_setpoints_after_mode_change(db, site_id, mode_code))
return SetSiteModeResponse(
success=True, mode=mode_code, activated_at=activated_at
)
async def _export_setpoints_after_mode_change(
pool: asyncpg.Pool, site_id: int, mode_code: str
) -> None:
try:
async with pool.acquire() as conn:
await export_setpoints(site_id, conn)
logger.info(
"Immediate control export after mode change applied (site=%s, mode=%s)",
site_id,
mode_code,
)
except Exception:
logger.exception(
"Immediate control export after mode change failed (site=%s, mode=%s)",
site_id,
mode_code,
)