Files
ems/backend/services/notification_service.py
Dusan Vojacek 5fcc47bce2
All checks were successful
test / smoke-test (push) Successful in 5s
deploy / deploy (push) Successful in 11s
implementace Ekonomiky
2026-04-05 20:10:43 +02:00

96 lines
2.8 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Discord a další notifikace pro provoz EMS."""
from __future__ import annotations
import logging
import httpx
from app.config import get_settings
logger = logging.getLogger(__name__)
async def send_discord(message: str, level: str = "info") -> bool:
"""
Pošle notifikaci na Discord webhook.
level: 'info', 'warning', 'error', 'critical'
Vrátí True při úspěchu.
"""
settings = get_settings()
webhook_url = settings.discord_webhook_url
if not webhook_url:
logger.debug("Discord webhook not configured, skipping notification")
return False
emoji = {"info": "", "warning": "⚠️", "error": "", "critical": "🚨"}.get(level, "")
try:
async with httpx.AsyncClient(timeout=10) as client:
resp = await client.post(
webhook_url,
json={
"content": f"{emoji} **EMS Alert** [{level.upper()}]\n{message}",
},
)
resp.raise_for_status()
return True
except Exception as e:
logger.warning("Discord notification failed: %s", e)
return False
async def notify_modbus_mismatch(
asset_code: str,
register: int,
register_name: str,
value_written: int,
value_verified: int,
attempt: int,
) -> None:
msg = (
f"Modbus mismatch na **{asset_code}**\n"
f"Registr: `0x{register:04X}` ({register_name})\n"
f"Zapsáno: `{value_written}` | Přečteno: `{value_verified}`\n"
f"Pokus č. {attempt}"
)
await send_discord(msg, level="error")
async def notify_self_sustain_activated(site_code: str, reason: str) -> None:
msg = (
f"Přepnutí na **SELF_SUSTAIN** lokalita `{site_code}`\n"
f"Důvod: {reason}"
)
await send_discord(msg, level="critical")
async def notify_daily_economics(
site_code: str,
day: str,
import_kwh: float,
import_cost: float,
export_kwh: float,
export_revenue: float,
green_bonus: float,
total_balance: float,
planned_balance: float | None,
) -> None:
lines = [
f"Ekonomika **{site_code}** {day}:",
f" Import: {import_kwh:.1f} kWh = {import_cost:.2f}",
f" Export: {export_kwh:.1f} kWh = {export_revenue:.2f}",
]
if green_bonus > 0:
lines.append(f" Zelený bonus: {green_bonus:.2f}")
sign = "+" if total_balance >= 0 else ""
lines.append(f" **BILANCE: {sign}{total_balance:.2f} Kč**")
if planned_balance is not None:
dev = total_balance - planned_balance
dev_sign = "+" if dev >= 0 else ""
lines.append(
f" Plán předpokládal: {planned_balance:+.2f}"
f"(odchylka {dev_sign}{dev:.2f} Kč)"
)
await send_discord("\n".join(lines), level="info")