503 lines
16 KiB
C++
Executable File
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
|