// SPDX-License-Identifier: GPL-3.0-or-later // Copyright (C) 2025 - 2026, Patrick Schurig / ETM PowerSync #include "optimizerstatus.h" #include #include namespace OptimizerStatus { bool Vivacite::noter(Evenement e, const QString &code, const QDateTime &instant) { const bool avant = m_vivant; switch (e) { case Evenement::PlanValide: m_vivant = true; m_echecs = 0; m_dernierPlanA = instant; break; case Evenement::Abstention: // L'optimiseur a répondu : la série d'échecs est rompue. Il ne planifie pas pour autant — // un optimiseur mort qui s'abstient reste mort jusqu'à son premier plan valide. m_echecs = 0; break; case Evenement::Echec: ++m_echecs; if (!code.isEmpty()) m_dernierCode = code; if (m_echecs >= EchecsAvantMort) m_vivant = false; break; case Evenement::ConnexionPerdue: m_vivant = false; if (!code.isEmpty()) m_dernierCode = code; break; } return m_vivant != avant; } QString strategieActive(bool degrade, bool vivant, const QString &strategieDuCycle) { if (degrade) return QString::fromLatin1(StrategieAucune); if (!vivant && strategieDuCycle == QLatin1String(StrategieOptimiseur)) return QString::fromLatin1(StrategieRegles); return strategieDuCycle; } namespace { bool listeDeCodes(const QVariant &v, const QStringList &connus, QVariantList *out) { if (v.userType() != QMetaType::QVariantList && v.userType() != QMetaType::QStringList) return false; for (const QVariant &x : v.toList()) { if (x.userType() != QMetaType::QString || !connus.contains(x.toString())) continue; // un code inconnu ou une valeur non textuelle n'est pas recopiée if (!out->contains(x)) out->append(x); } return true; } } QVariantMap capacitesPubliees(const QVariantMap &capabilities) { static const QStringList kinds{QStringLiteral("setpoint"), QStringLiteral("state"), QStringLiteral("constraint")}; static const QStringList sources{QStringLiteral("pv"), QStringLiteral("baseload"), QStringLiteral("price"), QStringLiteral("temperature")}; QVariantMap out; for (const char *cle : {"maxHorizonH", "resolutionS"}) { const QVariant v = capabilities.value(QLatin1String(cle)); bool ok = false; const double d = v.toDouble(&ok); const bool nombre = v.userType() == QMetaType::Double || v.userType() == QMetaType::Int || v.userType() == QMetaType::LongLong || v.userType() == QMetaType::UInt || v.userType() == QMetaType::ULongLong; if (nombre && ok && std::isfinite(d) && d >= 0) out.insert(QLatin1String(cle), d); } QVariantList l; if (listeDeCodes(capabilities.value(QStringLiteral("kinds")), kinds, &l)) out.insert(QStringLiteral("kinds"), l); l.clear(); if (listeDeCodes(capabilities.value(QStringLiteral("usesForecast")), sources, &l)) out.insert(QStringLiteral("usesForecast"), l); if (capabilities.value(QStringLiteral("reasonCodes")).userType() == QMetaType::Bool) out.insert(QStringLiteral("reasonCodes"), capabilities.value(QStringLiteral("reasonCodes")).toBool()); return out; } QString identite(const QString &texte, int max) { QString s; s.reserve(texte.size()); for (const QChar c : texte) s.append(c.category() == QChar::Other_Control || c.category() == QChar::Other_Format || c.category() == QChar::Separator_Line || c.category() == QChar::Separator_Paragraph ? QChar(' ') : c); return s.simplified().left(max); } }