From e42569f62972dae53c83fc949f5da35e1b99f7cb Mon Sep 17 00:00:00 2001 From: Dusan Vojacek Date: Thu, 11 Jun 2026 16:35:25 +0200 Subject: [PATCH] =?UTF-8?q?Re=C5=BEimy:=20okam=C5=BEit=C3=A1=20exekuce=20s?= =?UTF-8?q?etpoint=C5=AF=20po=20ru=C4=8Dn=C3=ADm=20p=C5=99epnut=C3=AD=20m?= =?UTF-8?q?=C3=B3du?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- backend/app/main.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/backend/app/main.py b/backend/app/main.py index d5400a1..d96e53c 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -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, + )