Files
qt5-legatus-legacy/Lts/Proxies/Buildings/BuildingControlUnit/ControlEffects/handeleffects.cpp
T
2026-08-13 18:33:10 +02:00

503 lines
16 KiB
C++
Executable File

/**
* @RDE_HEADER@
* Effects (plural) handler, handles all effects at one EGCU or BSM
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLTE, 2021-06-02
*/
#include "handeleffects.h"
#include "handeleffect.h"
#include "handle_http_request.h"
#include <QTimer>
#include <QUrlQuery>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDateTime>
#include <QJsonArray>
#include <QDateTime>
namespace BuildingControlUnit
{
HandelEffects::HandelEffects(QObject *parent, const QString &loggerchannel)
: QObject(parent)
, m_sounds(EffectOverride::EO_Auto)
, m_getRelayStateTimer(new QTimer(this))
, m_logger(getLogger(QStringLiteral("HandelEffects.") + loggerchannel))
{
DEBUG_LOG(m_logger) << "HandelEffects::init loggerchannel=" << loggerchannel;
// create a timer
// setup signal and slot
connect(m_getRelayStateTimer, &QTimer::timeout,
this, &HandelEffects::onRelayStateTimerTimeout);
}
HandelEffects::~HandelEffects()
{
}
void HandelEffects::init(const QString &controlEffectsCfg, const QString &hostname, EffectType et)
{
m_xmlReader.init(controlEffectsCfg);
DEBUG_LOG(m_logger) << "HandelEffects::init";
m_hostname = hostname;
m_lastDamage = -1;
m_effectType = et;
// msec
if (et == ET_Relay)
m_getRelayStateTimer->start(contents().updateRelayState);
}
void HandelEffects::startEffects(int damagePercent)
{
if (m_lastDamage == damagePercent)
{
DEBUG_LOG(m_logger) << "damagePercent=" << damagePercent
<< " m_lastDamage=" << m_lastDamage
<< " return";
return;
}
for (Effect *e : contents().constEffects())
{
// If this Instance does not handle BSM, skip BSM-Effects
if (e->effectType == ET_BsmFlash && m_effectType != ET_BsmFlash)
continue;
// If this Instance has BSM API, it is only for BSM, so skip sounds
if (e->effectType == ET_BackgroundSound && m_effectType == ET_BsmFlash)
continue;
// If this Instance has BSM API, it is only for BSM, so skip relays
if (e->effectType == ET_Relay && m_effectType == ET_BsmFlash)
continue;
DEBUG_LOG(m_logger) << "- HandelEffects::Starting Effect " << e << " of Type " << e->effectType << ". ----"
<< " name=" << e->name;
for (const Range *range : e->constRanges())
{
if (!range->fits(damagePercent))
continue;
if (range->fits(m_lastDamage) && !range->restartOnChange)
continue;
// We must restart the actions for that range. Either, because the range changed or because restart is commanded.
// Thus, we kill the old HandelEffect and start over.
createEffectHandler(e, range);
}
DEBUG_LOG(m_logger) << "- End Effect ";
}
m_lastDamage = damagePercent;
}
void HandelEffects::createEffectHandler(Effect *e, const Range *range)
{
HandelEffect *handelEffect = e->effectHandler;
delete handelEffect; // This also deletes the child handelEffect in case of Repeat actions!
handelEffect = new HandelEffect(this, m_hostname.isEmpty() ? QLatin1String("BSM") : m_hostname);
e->effectHandler = handelEffect;
if (e->override == EO_Auto)
{
if (m_effectType == ET_BsmFlash)
{
INFO_LOG(m_logger) << "setOverrides connect Flashes" ;
connect(handelEffect, &HandelEffect::triggerAllFlashlights, this, &HandelEffects::triggerAllFlashlights, Qt::UniqueConnection);
}
else
connect(handelEffect, &HandelEffect::newHttpRequest, this, &HandelEffects::sendHttpRequest, Qt::UniqueConnection);
}
connect(handelEffect, &HandelEffect::effectReady, this, &HandelEffects::onEffectReady);
DEBUG_LOG(m_logger) << "-- HandelEffects::Starting Range " << range->min << " - " << range->max
<< ". ----";
DEBUG_LOG(m_logger) << "-- Range has " << range->actions.count() << " actions";
handelEffect->init(range->actions, 1);
QTimer::singleShot(0, handelEffect, &HandelEffect::handleEffect);
DEBUG_LOG(m_logger) << "-- End Range ";
}
void HandelEffects::playHitSound(const int hitSoundId)
{
if (m_sounds == EffectOverride::EO_Off)
return;
QUrl url = XmlReader::createPreparedUrl(contents(), m_hostname);
url.setPath(QStringLiteral("/hitsound.php"));
QUrlQuery query;
query.addQueryItem(QStringLiteral("sound"), QString::number(hitSoundId));
query.addQueryItem(QStringLiteral("vol"), QString::number(contents().hitSoundVolume));
url.setQuery(query);
emit newHttpRequest(url, HandleHttpQueueMessageStatus::MS_Single);
}
void HandelEffects::switchRelay(const SwitchRelayValues &switchRelayValues)
{
QUrl url = XmlReader::createPreparedUrl(contents(), m_hostname);
url.setPath(QStringLiteral("/relay.php"));
QUrlQuery query;
query.addQueryItem(QStringLiteral("number"), QString::number(switchRelayValues.id));
query.addQueryItem(QStringLiteral("state"), QString::number(switchRelayValues.bcuRelayState));
if (switchRelayValues.bcuRelayState == BRS_Pulse)
{
query.addQueryItem(QStringLiteral("pulse"), QString::number(switchRelayValues.pulse));
query.addQueryItem(QStringLiteral("repeat"), QString::number(switchRelayValues.count-1));
query.addQueryItem(QStringLiteral("delay"), QString::number(switchRelayValues.delay));
}
url.setQuery(query);
emit newHttpRequest(url, HandleHttpQueueMessageStatus::MS_Single);
}
void HandelEffects::setOverrides(const QVector<BcuEffectState> &effectStates)
{
m_effectStates = effectStates; // Save effectStates to restore overrides
DEBUG_LOG(m_logger) << "In set overrides for " << m_hostname << ", effectStates.size: " << effectStates.size();
for(const auto &es : qAsConst(m_effectStates))
{
DEBUG_LOG(m_logger) << "m_effectStates: es.id=" << es.id
<< ", es.type=" << es.type
<< ", es.override=" << es.effectOverride;
}
m_sounds = EffectOverride::EO_Auto;
DEBUG_LOG(m_logger) << "Nun die Schleife:";
for(const auto &es : qAsConst(effectStates))
{
DEBUG_LOG(m_logger) << "es.id=" << es.id
<< ", es.type=" << es.type
<< ", es.override=" << es.effectOverride;
switch (es.type) {
case BET_BackgroundSound:
{
for (Effect *e : contents().constEffects())
{
if (e->effectType != ET_BackgroundSound)
continue;
EffectOverride eo = static_cast<EffectOverride>(es.effectOverride);
e->override = eo;
m_sounds = eo;
if (eo == EO_Auto)
createEffectHandler(e,e->getRangeByDamagePercent(m_lastDamage));
else
{
if (e->effectHandler)
{
disconnect(e->effectHandler, &HandelEffect::newHttpRequest, this, &HandelEffects::sendHttpRequest);
INFO_LOG(m_logger) << "setOverrides emit triggerAllFlashlights(0,0,0,0)" ;
emit triggerAllFlashlights(0,0,0,0);
}
}
}
if (es.effectOverride == BEO_Off )
{
DEBUG_LOG(m_logger) << "BEO_Off";
// Stop all Sounds:
QUrl url = XmlReader::createPreparedUrl(contents(), m_hostname);
QUrlQuery query;
url.setPath(QStringLiteral("/bgsound.php"));
query.addQueryItem(QStringLiteral("control"), QString::number(BCS_Stop_All_Soundfiles));
query.addQueryItem(QStringLiteral("category"), QStringLiteral("people")); // dummy for ICD
query.addQueryItem(QStringLiteral("sound"), QStringLiteral("0")); // dummy for ICD
url.setQuery(query);
sendHttpRequest(url);
}
break;
}
case BET_Relay:
{
for (Effect *e : contents().constEffects())
{
if (e->effectType != ET_Relay)
continue;
if (e->id != es.id)
continue;
EffectOverride eo = static_cast<EffectOverride>(es.effectOverride);
if (eo == e->override)
//continue;
e->override = eo;
if (es.effectOverride != BEO_Auto)
{
SwitchRelayValues relayValues;
relayValues.id = e->id;
relayValues.bcuRelayState = static_cast<BcuRelayState>(es.effectOverride);
switchRelay(relayValues);
if (e->effectHandler)
disconnect(e->effectHandler, &HandelEffect::newHttpRequest, this, &HandelEffects::sendHttpRequest);
}
else
createEffectHandler(e,e->getRangeByDamagePercent(m_lastDamage));
}
break;
}
case BET_BsmFlash:
{
if (m_effectType != ET_BsmFlash)
break;
for (Effect *e : contents().constEffects())
{
if (e->effectType != ET_BsmFlash)
continue;
EffectOverride eo = static_cast<EffectOverride>(es.effectOverride);
if (eo == e->override)
continue;
e->override = eo;
if (es.effectOverride != BEO_Off) // -1 for back to auto or 1 for permanently on which in this case shall also be "auto"...
createEffectHandler(e,e->getRangeByDamagePercent(m_lastDamage));
else
{
if (e->effectHandler)
{
INFO_LOG(m_logger) << "setOverrides disconnect Flashes" ;
disconnect (e->effectHandler, &HandelEffect::triggerAllFlashlights, this, &HandelEffects::triggerAllFlashlights);
}
}
}
break;
}
default:
break;
}
}
}
QVector<BcuEffectState> HandelEffects::getOverrides()
{
QVector<BcuEffectState> overrides;
for (Effect *effect : contents().constEffects())
{
BcuEffectState override;
override.id = effect->id;
switch (effect->effectType)
{
case BuildingControlUnit::ET_Unset:
override.type = BET_Unset;
break;
case BuildingControlUnit::ET_Relay:
override.type = BET_Relay;
break;
case BuildingControlUnit::ET_BackgroundSound:
override.type = BET_BackgroundSound;
break;
case BuildingControlUnit::ET_BsmFlash:
override.type = BET_BsmFlash;
break;
} // switch
switch (effect->override)
{
case EO_Auto:
override.effectOverride = BEO_Auto;
break;
case EO_Off:
override.effectOverride = BEO_Off;
break;
case EO_On:
override.effectOverride = BEO_On;
break;
} // switch
DEBUG_LOG(m_logger) << "getOverrides "
<< " id=" << override.id
<< " type=" << override.type
<< " override" << override.effectOverride;
overrides.append(override);
} // for
return overrides;
} // END getOverrides
void HandelEffects::onEffectReady()
{
// Effect will delete itself, but we have to remove the pointer from the corresponding effect.
for (Effect *e : contents().constEffects())
{
if (e->effectHandler != sender())
continue;
e->effectHandler = nullptr;
return;
}
}
void HandelEffects::sendHttpRequest(const QUrl &url)
{
QUrl copy = url;
copy.setHost(m_hostname);
DEBUG_LOG(m_logger) << "sendHttpRequest" << copy.toString();
emit newHttpRequest(copy, HandleHttpQueueMessageStatus::MS_Single);
}
void HandelEffects::onRelayStateTimerTimeout()
{
if ( m_offlineCounter == 3 )
{
m_offlineState = true;
NOTICE_LOG(m_logger) << "!!!!!!!!! Send Offline State !!!!!!!!!!!!!!!! m_offlineState=" << m_offlineState;
m_relayState.offlineTime = QDateTime::currentMSecsSinceEpoch();
emit sendRelayState(m_relayState);
m_overridesSend = false;
}
DEBUG_LOG(m_logger) << "send get relay-State contents()=" << contents().toString()
<< " m_offlineCounter=" << m_offlineCounter;
QUrl url = XmlReader::createPreparedUrl(contents(), m_hostname);
url.setPath(QStringLiteral("/relay.php"));
QUrlQuery query;
query.addQueryItem(QStringLiteral("state"), QString::number(BRS_State));
url.setQuery(query);
emit newHttpRequest(url, HandleHttpQueueMessageStatus::MS_Cyclic);
m_offlineCounter++;
}
///////////////////////////////////////////////////
void HandelEffects::handleEgcuReplyObject(const QString &host, const QByteArray &data)
{
bool relayStateChanged = false;
TRACE_LOG(m_logger) << "handleEgcuReply Object:" << data
<< " m_offlineState=" << m_offlineState;
if (m_offlineState)
{
DEBUG_LOG(m_logger) << "State wiederherstellen !!!!!!!!!!! m_offlineState=" << m_offlineState;
m_offlineState = false;
setOverrides(m_effectStates);
}
RelayState lastRelayState = m_relayState;
m_relayState.relayStates.clear();
const QJsonObject jsonObject = QJsonDocument::fromJson(data).object();
const QJsonObject stateObj = jsonObject[QStringLiteral("State")].toObject();
for (auto it = stateObj.constBegin(); it != stateObj.constEnd(); ++it)
{
RelayStateInfo rsi;
rsi.id = it.key().toInt();
rsi.state = it.value().isString() ? (it.value().toString().compare(QLatin1String("on"), Qt::CaseInsensitive) == 0) : it.value().toBool(false);
m_relayState.relayStates.append(rsi);
TRACE_LOG(m_logger) << "id=" << rsi.id
<< " state=" << rsi.state;
}
if ( m_relayState.relayStates.size() == lastRelayState.relayStates.size())
{
for (int i = 0; i < m_relayState.relayStates.size(); ++i)
{
if (m_relayState.relayStates[i].state != lastRelayState.relayStates[i].state)
{
TRACE_LOG(m_logger) << "Values relayStateChanged = true";
relayStateChanged = true;
}
}
}
else
{
TRACE_LOG(m_logger) << "Size relayStateChanged = true";
relayStateChanged = true;
}
if ( m_offlineCounter > 1)
{
TRACE_LOG(m_logger) << "m_offlineCounter=" << m_offlineCounter;
relayStateChanged = true;
}
m_relayState.hostname = m_hostname;
m_relayState.stateTime = QDateTime::currentMSecsSinceEpoch();
m_relayState.offlineTime = 0;
m_offlineCounter=0;
DEBUG_LOG(m_logger) << "host=" << host.toLower()
<< " relayStateChanged=" << relayStateChanged
<< " m_overridesSend=" << m_overridesSend
<< " m_offlineState=" << m_offlineState;
// if ( m_relayState.hostname.toLower() == host.toLower() && relayStateChanged && m_overridesSend)
if ( m_offlineState)
{
NOTICE_LOG(m_logger) << "!!!!!!!!!!!!!!!! EGCU States wieder setzen !!!!!!!!!!!!!!!!!!";
m_offlineState = false;
}
if ( m_relayState.hostname.toLower() == host.toLower() && relayStateChanged)
{
DEBUG_LOG(m_logger) << "emit sendRelayState(m_relayState) relayStateChanged";
emit sendRelayState(m_relayState);
}
}
void HandelEffects::handleEgcuReplyArray(const QString &host, const QByteArray &data)
{
Q_UNUSED (host);
TRACE_LOG(m_logger) << "handleEgcuReply Array:" << data;
m_relayState.relayStates.clear();
//parse the reply JSON and send result to svcBuilding
const QJsonObject jsonObject = QJsonDocument::fromJson(data).object();
if (!jsonObject.contains(QStringLiteral("State")) )
return;
const QJsonArray stateArray = jsonObject[QStringLiteral("State")].toArray();
for (int i = 0; i < stateArray.size(); ++i)
{
RelayStateInfo rsi;
rsi.id = i;
rsi.state = stateArray[i].isString() ? (stateArray[i].toString().compare(QLatin1String("on"), Qt::CaseInsensitive)== 0 ): stateArray[i].toBool(false);
m_relayState.relayStates.append(rsi);
TRACE_LOG(m_logger) << "id=" << rsi.id
<< " state=" << rsi.state;
}
m_relayState.hostname = m_hostname;
m_relayState.stateTime = QDateTime::currentMSecsSinceEpoch();
m_relayState.offlineTime = 0;
m_offlineCounter=0;
// if ( m_relayState.hostname.toLower() == host.toLower() && relayStateChanged && m_overridesSend )
// emit sendRelayState(m_relayState);
}
void HandelEffects::handleEgcuReply(const QString &host, const QByteArray &data)
{
//parse the reply JSON and send result to svcBuilding
DEBUG_LOG(m_logger) << "HandelEffects::handleEgcuReply host=" << host
<< " m_hostname=" << m_hostname
<< " m_overridesSend=" << m_overridesSend;
if (host.toLower() != m_hostname.toLower())
return;
const QJsonObject jsonObject = QJsonDocument::fromJson(data).object();
if (!jsonObject.contains(QStringLiteral("State")) )
{
m_overridesSend = true;
TRACE_LOG(m_logger) << "No State return";
return;
}
const QJsonValue jsonValue = jsonObject[QStringLiteral("State")];
if (jsonValue.isArray())
{
TRACE_LOG(m_logger) << "data isArray\n";
handleEgcuReplyArray(host, data);
}
else
{
TRACE_LOG(m_logger) << "data isObject\n";
handleEgcuReplyObject(host, data);
}
}
} // BuildingControlUnit