Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
@@ -0,0 +1,49 @@
|
||||
#
|
||||
# $Id$
|
||||
# $HeadURL$
|
||||
# $Author$
|
||||
#
|
||||
|
||||
SET(co_SRCS
|
||||
xmlreader.cpp
|
||||
xmlreader.h
|
||||
handeleffects.cpp
|
||||
handeleffects.h
|
||||
handeleffect.cpp
|
||||
handeleffect.h
|
||||
)
|
||||
|
||||
SET(cot_SRCS
|
||||
xmlreader.cpp
|
||||
xmlreader.h
|
||||
effect_test_main.cpp
|
||||
)
|
||||
|
||||
NGL_ADD_LIBRARY2(AAR SV ControlEffects SHARED ${co_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(ControlEffects
|
||||
NGLLogger
|
||||
Qt5::Concurrent
|
||||
Qt5::Core
|
||||
# Qt5::Test
|
||||
Qt5::Xml
|
||||
Qt5::Network
|
||||
BuildingControlCommon
|
||||
BuildingControlVwm
|
||||
BuildingControlBsm
|
||||
nglcoreapplication
|
||||
)
|
||||
|
||||
NGL_ADD_EXECUTABLE(AAR SV ControlEffectsTest ${cot_SRCS})
|
||||
NGL_TARGET_LINK_LIBRARIES(ControlEffectsTest
|
||||
NGLLogger
|
||||
Qt5::Concurrent
|
||||
Qt5::Core
|
||||
# Qt5::Test
|
||||
Qt5::Xml
|
||||
Qt5::Network
|
||||
BuildingControlCommon
|
||||
BuildingControlVwm
|
||||
nglcoreapplication
|
||||
)
|
||||
NGL_INSTALL_TARGET(ControlEffectsTest)
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Kleines Testprogramm für BSMs
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Gerlinde Rudolphus, SLSA, 2013-03-05
|
||||
*/
|
||||
|
||||
#include <nglapplication/nglcoreapplication.h>
|
||||
#include <QNetworkProxy>
|
||||
#include <memory>
|
||||
#include <settings.h>
|
||||
#include "xmlreader.h"
|
||||
#include "logger.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// QString hostname = QStringLiteral("ubeecu0002");
|
||||
NGLCoreApplication app(argc, argv);
|
||||
QNetworkProxy::setApplicationProxy(QNetworkProxy());
|
||||
app.createLogger("BCU");
|
||||
BuildingControlUnit::XmlReader *xmlReader = new BuildingControlUnit::XmlReader();
|
||||
//BuildingControlUnit::HandelEffects * handelEffects = new BuildingControlUnit::HandelEffects();
|
||||
//BuildingControlUnit::HandleHttpRequest * handleHttpRequest = new BuildingControlUnit::HandleHttpRequest;
|
||||
//QString filename = "C:/HomeOffice/Buildings/BuildingControlUnit/effect_config.xml";
|
||||
//QString filename = "/shd/CTC/TOOLS/HomeOffice/Malte1/Personen/effect_config.xml";
|
||||
//QString filename = "/shd/CTC/TOOLS/TDS/TDS-source/Lts/Proxies/Buildings/BuildingControlUnit/effect_config.xml";
|
||||
QString filename = QStringLiteral("/tmp/effect_config.xml");
|
||||
|
||||
xmlReader->init(filename);
|
||||
|
||||
//handelEffects->init(filename, hostname);
|
||||
//handelEffects->printEffects();
|
||||
//qDebug() << "---------------------------------------------";
|
||||
//qDebug() << "--- Start Effects: ---";
|
||||
//qDebug() << "---------------------------------------------";
|
||||
//handelEffects->startEffects(80);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* One Effect Handler. Destroyed/created on Range change
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Gerlinde Rudolphus, SLTE, 2021-05-31
|
||||
*/
|
||||
|
||||
#include "handeleffect.h"
|
||||
#include <QUrlQuery>
|
||||
#include <QTimer>
|
||||
|
||||
namespace BuildingControlUnit
|
||||
{
|
||||
|
||||
HandelEffect::HandelEffect(QObject *parent, const QString &loggerchannel)
|
||||
: QObject(parent)
|
||||
, m_logger(getLogger(QStringLiteral("HandelSingleEffect.") + loggerchannel))
|
||||
{
|
||||
}
|
||||
|
||||
bool HandelEffect::init(const QVector<Action *> &actions, int repetitions = 1)
|
||||
{
|
||||
if (actions.isEmpty())
|
||||
return false;
|
||||
|
||||
m_actions = actions;
|
||||
m_currentAction = nullptr;
|
||||
m_repeatCount = repetitions; // Usually The action list is only worked over once.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//void handleEffect(const Effect *effect, QVector<Action *> actions, int damage, bool background);
|
||||
void HandelEffect::handleEffect()
|
||||
{
|
||||
// No current Action? Start over or be ready
|
||||
if (!m_currentAction)
|
||||
{
|
||||
// Infinite Repeat Actions must start with repeatCount = -1
|
||||
if (m_repeatCount != 0)
|
||||
{
|
||||
m_currentAction = m_actions.first();
|
||||
--m_repeatCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
emit effectReady();
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = m_actions.indexOf(m_currentAction);
|
||||
++index;
|
||||
m_currentAction = m_actions.value(index, nullptr);
|
||||
if (!m_currentAction)
|
||||
{
|
||||
QTimer::singleShot(0, this, &HandelEffect::handleEffect);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (m_currentAction->aclass)
|
||||
{
|
||||
case AC_Unset:
|
||||
DEBUG_LOG(m_logger) << "---- This is unset ----";
|
||||
break;
|
||||
case AC_Standard:
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "---- This is a standard Action ----";
|
||||
if (!m_currentAction->url.isEmpty())
|
||||
{
|
||||
// Todo: Is there a standard action valid for BSM? If so, we need to consider!
|
||||
DEBUG_LOG(m_logger) << "---- emit newHttpRequest(a->url):" << m_currentAction->url.toString();
|
||||
emit newHttpRequest(m_currentAction->url);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case AC_Repeat:
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "---- This is a Repeat Action";
|
||||
const RepeatAction *ra = static_cast<const RepeatAction *>(m_currentAction);
|
||||
|
||||
HandelEffect *he = new HandelEffect(this);
|
||||
he->init(ra->actions, ra->count);
|
||||
connect(he, &HandelEffect::effectReady, this, &HandelEffect::handleEffect);
|
||||
connect(he, &HandelEffect::newHttpRequest, this, &HandelEffect::newHttpRequest);
|
||||
connect(he, &HandelEffect::triggerAllFlashlights, this, &HandelEffect::triggerAllFlashlights);
|
||||
QTimer::singleShot(0, he, &HandelEffect::handleEffect);
|
||||
// To avoid the Timer call at the end of this method:
|
||||
return;
|
||||
// So this instance does nothing unless child-he is ready.
|
||||
}
|
||||
case AC_Pause:
|
||||
{
|
||||
const PauseAction *pa = static_cast<const PauseAction *>(m_currentAction);
|
||||
DEBUG_LOG(m_logger) << "---- This is a Pause Action Pause=" << pa->pause
|
||||
<< " comment=" << pa->comment;
|
||||
|
||||
QTimer::singleShot(pa->pause, this, &HandelEffect::handleEffect);
|
||||
// To avoid the Timer call at the end of this method:
|
||||
return;
|
||||
// So this instance does nothing unless timer returns.
|
||||
}
|
||||
case AC_Bsm:
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "---- This is a Bsm Action ";
|
||||
const BsmAction *ba = static_cast<const BsmAction*>(m_currentAction);
|
||||
if (!ba->isNull())
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "emit triggerAllFlashlights ------ atype=" << m_currentAction->atype
|
||||
<< " pause=" << ba->pause
|
||||
<< " choplength=" << ba->choplength
|
||||
<< " pulses=" << ba->pulses
|
||||
<< " pulseduration=" << ba->pulseduration
|
||||
<< " comment=" << ba->comment
|
||||
<< " this: " << this;
|
||||
emit triggerAllFlashlights(ba->pulses, ba->pause, ba->choplength, ba->pulseduration);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "--- End Action ";
|
||||
|
||||
// Start next action with ending this method.
|
||||
QTimer::singleShot(0, this, &HandelEffect::handleEffect);
|
||||
} // end printActions
|
||||
|
||||
} //namespace BuildingControlUnit
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* One Effect Handler. Destroyed/created on Range change
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Gerlinde Rudolphus, SLTE, 2021-05-31
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xmlreader.h"
|
||||
#include <logger.h>
|
||||
|
||||
namespace BuildingControlUnit
|
||||
{
|
||||
|
||||
class HandelEffect: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
HandelEffect(QObject* parent = nullptr, const QString &loggerchannel = QString());
|
||||
|
||||
bool init(const QVector<Action*> &actions, int repetitions);
|
||||
|
||||
signals:
|
||||
void newHttpRequest(const QUrl &url);
|
||||
void triggerAllFlashlights(int numberOfFlashes,
|
||||
int pauseDuration,
|
||||
int choppedConfiguration,
|
||||
int flashDuration);
|
||||
void effectReady();
|
||||
|
||||
public slots:
|
||||
void handleEffect();
|
||||
|
||||
private:
|
||||
QVector<Action *> m_actions;
|
||||
Action *m_currentAction{nullptr};
|
||||
int m_repeatCount{1};
|
||||
LOGGER_T m_logger;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
+502
@@ -0,0 +1,502 @@
|
||||
/**
|
||||
* @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
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Effects (plural) handler, handles all effects at one EGCU or BSM
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Gerlinde Rudolphus, SLTE, 2021-06-02
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xmlreader.h"
|
||||
|
||||
#include <ControlEffects/controleffects_export.h>
|
||||
#include <BSM/bsm_types.h>
|
||||
#include <logger.h>
|
||||
#include "handle_http_request.h"
|
||||
class QTimer;
|
||||
|
||||
namespace BuildingControlUnit
|
||||
{
|
||||
|
||||
class CONTROLEFFECTS_EXPORT HandelEffects: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HandelEffects(QObject *parent = nullptr, const QString &loggerchannel = QString());
|
||||
~HandelEffects();
|
||||
|
||||
void init(const QString &controlEffectsCfg, const QString &hostname, EffectType et);
|
||||
void startEffects(int damagePercent);
|
||||
void playHitSound(const int hitSoundId);
|
||||
void switchRelay(const SwitchRelayValues &switchRelayValues);
|
||||
QString hostname() const { return m_hostname; }
|
||||
void setOverrides(const QVector<BcuEffectState> &effectStates);
|
||||
QVector<BcuEffectState> getOverrides();
|
||||
|
||||
public slots:
|
||||
void handleEgcuReply(const QString &host, const QByteArray &data);
|
||||
|
||||
private slots:
|
||||
void onEffectReady();
|
||||
void sendHttpRequest(const QUrl &url);
|
||||
void onRelayStateTimerTimeout();
|
||||
|
||||
private:
|
||||
void handleEgcuReplyObject(const QString &host, const QByteArray &data);
|
||||
void handleEgcuReplyArray(const QString &host, const QByteArray &data);
|
||||
|
||||
|
||||
signals:
|
||||
void newHttpRequest(const QUrl &url, HandleHttpQueueMessageStatus status);
|
||||
void triggerAllFlashlights(int numberOfFlashes,
|
||||
int pauseDuration,
|
||||
int choppedConfiguration,
|
||||
int flashDuration);
|
||||
void sendRelayState (const RelayState &relayState);
|
||||
|
||||
private:
|
||||
XmlContents contents() const { return m_xmlReader.contents(); }
|
||||
int m_lastDamage = -1;
|
||||
XmlReader m_xmlReader;
|
||||
EffectType m_effectType; // BSM or Sound/Relay [EGCU]
|
||||
QString m_hostname;
|
||||
EffectOverride m_sounds;
|
||||
QTimer *m_getRelayStateTimer;
|
||||
RelayState m_relayState;
|
||||
int m_offlineCounter = 0;
|
||||
LOGGER_T m_logger;
|
||||
|
||||
QVector<BcuEffectState> m_effectStates;
|
||||
bool m_overridesSend = false;
|
||||
//bool m_reconnected = false; // New Connection to EGCU => restore the target state of the EGCU
|
||||
bool m_offlineState = true;
|
||||
void createEffectHandler(Effect *e, const Range *range);
|
||||
};
|
||||
|
||||
} // BuildingControlUnit
|
||||
@@ -0,0 +1,30 @@
|
||||
#include <QApplication>
|
||||
#include "xmlreader.h"
|
||||
#include "handeleffects.h"
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
HandelEffects *handelEffects = new HandelEffects();
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
//QString filename = "C:/HomeOffice/Buildings/BuildingControlUnit/effect_config.xml";
|
||||
//QString filename = "/shd/CTC/TOOLS/HomeOffice/Malte1/Personen/effect_config.xml";
|
||||
//QString filename = "/shd/CTC/TOOLS/TDS/TDS-source/Lts/Proxies/Buildings/BuildingControlUnit/effect_config.xml";
|
||||
QString filename = "/shd/CTC/TOOLS/HomeOffice/Malte3/Personen1/effect_config.xml";
|
||||
|
||||
|
||||
handelEffects->init(filename);
|
||||
handelEffects->printEffects();
|
||||
qDebug() << "---------------------------------------------";
|
||||
qDebug() << "--- Start Effects: ---";
|
||||
qDebug() << "---------------------------------------------";
|
||||
handelEffects->startEffects(80);
|
||||
//handelEffects->newSegmentDamage(80);
|
||||
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
@@ -0,0 +1,478 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Xml Reader for Effect Configuration
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Gerlinde Rudolphus, SLTE, 2021-06-02
|
||||
*/
|
||||
|
||||
#include "xmlreader.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QUrlQuery>
|
||||
#include <QXmlStreamAttributes>
|
||||
|
||||
namespace BuildingControlUnit
|
||||
{
|
||||
|
||||
XmlReader::XmlReader(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("XmlReader"))
|
||||
{
|
||||
}
|
||||
|
||||
bool XmlReader::init(const QString &effectConfigFile)
|
||||
{
|
||||
m_contents.effects.clear();
|
||||
|
||||
QFile file(effectConfigFile);
|
||||
DEBUG_LOG(m_logger) << "open effectConfigFile: " << effectConfigFile;
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "Couldn't open EffectConfigFile: " << effectConfigFile;
|
||||
return false;
|
||||
}
|
||||
|
||||
QXmlStreamReader xml(file.readAll());
|
||||
while (!xml.atEnd() && !xml.hasError())
|
||||
{
|
||||
QXmlStreamReader::TokenType token = xml.readNext();
|
||||
if (token == QXmlStreamReader::StartDocument)
|
||||
continue;
|
||||
else if (token == QXmlStreamReader::StartElement)
|
||||
{
|
||||
if (xml.name() == QStringLiteral("effects"))
|
||||
continue;
|
||||
else if (xml.name() == QStringLiteral("backgroundSoundVolume"))
|
||||
m_contents.bgSoundVolume = xml.readElementText().toInt();
|
||||
else if (xml.name() == QStringLiteral("hitSoundVolume"))
|
||||
m_contents.hitSoundVolume = xml.readElementText().toInt();
|
||||
else if (xml.name() == QStringLiteral("password"))
|
||||
m_contents.password = xml.readElementText();
|
||||
else if (xml.name() == QStringLiteral("port"))
|
||||
m_contents.port = xml.readElementText().toInt();
|
||||
else if (xml.name() == QStringLiteral("username"))
|
||||
m_contents.username = xml.readElementText();
|
||||
else if (xml.name() == QStringLiteral("updateRelayState"))
|
||||
m_contents.updateRelayState = xml.readElementText().toInt();
|
||||
|
||||
if (xml.name() == QStringLiteral("effect"))
|
||||
{
|
||||
Effect *e = this->parseEffect(xml);
|
||||
if (e)
|
||||
m_contents.effects.append(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (xml.hasError())
|
||||
{
|
||||
ERROR_LOG(m_logger) << "Effect Config File had XML Errors:\n" << xml.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "Effect Config File Contents: " << m_contents.toString();
|
||||
createHttpRequests();
|
||||
return true;
|
||||
}
|
||||
|
||||
Effect *XmlReader::parseEffect(QXmlStreamReader &xml)
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "- parseEffect Start";
|
||||
|
||||
if (xml.tokenType() != QXmlStreamReader::StartElement ||
|
||||
xml.name() != QStringLiteral("effect"))
|
||||
return {};
|
||||
|
||||
Effect *e = new Effect();
|
||||
QXmlStreamAttributes attributes = xml.attributes();
|
||||
|
||||
if (attributes.hasAttribute(QStringLiteral("type")))
|
||||
{
|
||||
QString typeString = attributes.value(QStringLiteral("type")).toString();
|
||||
if (typeString == QStringLiteral("relayAction"))
|
||||
e->effectType = ET_Relay;
|
||||
else if (typeString == QStringLiteral("backgroundSoundAction"))
|
||||
e->effectType = ET_BackgroundSound;
|
||||
else if (typeString == QStringLiteral("bsmFlashAction"))
|
||||
e->effectType = ET_BsmFlash;
|
||||
}
|
||||
xml.readNext();
|
||||
|
||||
while (!(xml.tokenType() == QXmlStreamReader::EndElement &&
|
||||
xml.name() == QStringLiteral("effect")))
|
||||
{
|
||||
if (xml.tokenType() == QXmlStreamReader::StartElement)
|
||||
{
|
||||
if (xml.name() == QStringLiteral("id"))
|
||||
{
|
||||
QXmlStreamAttributes attributesName = xml.attributes();
|
||||
if (attributesName.hasAttribute(QStringLiteral("name")))
|
||||
{
|
||||
e->name = attributesName.value(QStringLiteral("name")).toString();
|
||||
}
|
||||
e->id = xml.readElementText().toInt();
|
||||
}
|
||||
|
||||
if (xml.name() == QStringLiteral("category"))
|
||||
{
|
||||
e->category = static_cast<Category>(xml.readElementText().toInt());
|
||||
}
|
||||
|
||||
if (xml.name() == QStringLiteral("override"))
|
||||
{
|
||||
e->override = static_cast<EffectOverride>(xml.readElementText().toInt());
|
||||
}
|
||||
|
||||
if (xml.name() == QStringLiteral("range"))
|
||||
e->ranges.append(parseRange(xml));
|
||||
}
|
||||
xml.readNext();
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "- parseEffect: Name: " << e->id
|
||||
<< ", Type: " << e->effectType
|
||||
<< ", Category: " << e->category
|
||||
<< ", Name: " << e->name
|
||||
<< ", override: " << e->override;
|
||||
DEBUG_LOG(m_logger) << "- parseEffect End. It has " << e->ranges.size() << " ranges";
|
||||
return e;
|
||||
}
|
||||
|
||||
Range *XmlReader::parseRange(QXmlStreamReader &xml)
|
||||
{
|
||||
if (xml.tokenType() != QXmlStreamReader::StartElement ||
|
||||
xml.name() != QStringLiteral("range"))
|
||||
return {};
|
||||
|
||||
DEBUG_LOG(m_logger) << "-- parseRange Start";
|
||||
Range *r = new Range();
|
||||
|
||||
QXmlStreamAttributes attributes = xml.attributes();
|
||||
|
||||
if (attributes.hasAttribute(QStringLiteral("min")))
|
||||
r->min = attributes.value(QStringLiteral("min")).toInt();
|
||||
if (attributes.hasAttribute(QStringLiteral("max")))
|
||||
r->max = attributes.value(QStringLiteral("max")).toInt();
|
||||
if (attributes.hasAttribute(QStringLiteral("restartOnChange")))
|
||||
r->restartOnChange = attributes.value(QLatin1String("restartOnChange")).toString().toLower() == QLatin1String("true");
|
||||
|
||||
xml.readNext();
|
||||
/*
|
||||
* We're going to loop over the things because the order might change.
|
||||
* We'll continue the loop until we hit an EndElement named person.
|
||||
*/
|
||||
while (!(xml.tokenType() == QXmlStreamReader::EndElement &&
|
||||
xml.name() == QLatin1String("range")))
|
||||
{
|
||||
Action *a = parseAction(xml);
|
||||
if (a && a->aclass != AC_Unset)
|
||||
r->actions << a;
|
||||
|
||||
xml.readNext();
|
||||
}
|
||||
DEBUG_LOG(m_logger) << "-- parseRange: [" << r->min << "-" << r->max << "]"
|
||||
<< ", restartOnChange: " <<r->restartOnChange
|
||||
<< ", ActionCount: " << r->actions.count();
|
||||
DEBUG_LOG(m_logger) << "-- parseRange End";
|
||||
return r;
|
||||
}
|
||||
|
||||
Action *XmlReader::parseAction(QXmlStreamReader &xml)
|
||||
{
|
||||
if (xml.tokenType() != QXmlStreamReader::StartElement)
|
||||
return {};
|
||||
|
||||
if (xml.name() == QStringLiteral("action"))
|
||||
return parseStandardAction(xml);;
|
||||
|
||||
if (xml.name() == QStringLiteral("pause"))
|
||||
return parsePauseAction(xml);
|
||||
|
||||
if (xml.name() == QStringLiteral("repeat"))
|
||||
return parseRepeatAction(xml);
|
||||
|
||||
if (xml.name() == QStringLiteral("bsm"))
|
||||
return parseBsmAction(xml);
|
||||
|
||||
WARNING_LOG(m_logger) << "--- parseUnknownAction with name '" << xml.name().string() << "'cannot be handled.";
|
||||
return {};
|
||||
}
|
||||
|
||||
PauseAction *XmlReader::parsePauseAction(QXmlStreamReader &xml)
|
||||
{
|
||||
if (xml.tokenType() != QXmlStreamReader::StartElement ||
|
||||
xml.name() != QLatin1String("pause"))
|
||||
return {};
|
||||
|
||||
DEBUG_LOG(m_logger) << "--- parsePauseAction Start";
|
||||
QXmlStreamAttributes attributes = xml.attributes();
|
||||
PauseAction *p = new PauseAction();
|
||||
p->atype = static_cast<ActionType>(attributes.value(QStringLiteral("type")).toInt());
|
||||
if (attributes.hasAttribute(QStringLiteral("comment")))
|
||||
p->comment = attributes.value(QStringLiteral("comment")).toString();
|
||||
p->pause = xml.readElementText().toInt();
|
||||
DEBUG_LOG(m_logger) << "--- parsePauseAction: "
|
||||
<< " Pause: " << p->pause
|
||||
<< ", Comment: " << p->comment;
|
||||
|
||||
DEBUG_LOG(m_logger) << "--- parsePauseAction End";
|
||||
return p;
|
||||
}
|
||||
|
||||
RepeatAction *XmlReader::parseRepeatAction(QXmlStreamReader &xml)
|
||||
{
|
||||
if (xml.tokenType() != QXmlStreamReader::StartElement ||
|
||||
xml.name() != QStringLiteral("repeat"))
|
||||
return {};
|
||||
DEBUG_LOG(m_logger) << "--- parseRepeatAction Start";
|
||||
RepeatAction *ra = new RepeatAction();
|
||||
QXmlStreamAttributes attributes = xml.attributes();
|
||||
|
||||
if (attributes.hasAttribute(QStringLiteral("count")))
|
||||
ra->count = attributes.value(QStringLiteral("count")).toInt();
|
||||
if (attributes.hasAttribute(QStringLiteral("comment")))
|
||||
ra->comment = attributes.value(QStringLiteral("comment")).toString();
|
||||
|
||||
if (ra->count == 0)
|
||||
ra->count = -1;
|
||||
|
||||
xml.readNext();
|
||||
|
||||
while (!(xml.tokenType() == QXmlStreamReader::EndElement &&
|
||||
xml.name() == QStringLiteral("repeat")))
|
||||
{
|
||||
Action *a = parseAction(xml);
|
||||
if (a && a->aclass != AC_Unset)
|
||||
ra->actions << a;
|
||||
xml.readNext();
|
||||
}
|
||||
|
||||
QString repetitions = QString::number(ra->count);
|
||||
if (ra->count < 0)
|
||||
repetitions = QLatin1String("Infinite");
|
||||
DEBUG_LOG(m_logger) << "--- parseRepeatAction: Repetitions: " << repetitions << ", Comment: " << ra->comment;
|
||||
DEBUG_LOG(m_logger) << "--- parseRepeatAction End";
|
||||
return ra;
|
||||
}
|
||||
|
||||
Action *XmlReader::parseStandardAction(QXmlStreamReader &xml)
|
||||
{
|
||||
|
||||
if (xml.tokenType() != QXmlStreamReader::StartElement ||
|
||||
xml.name() != QStringLiteral("action"))
|
||||
return {};
|
||||
|
||||
DEBUG_LOG(m_logger) << "--- parseStandardAction Start";
|
||||
|
||||
QXmlStreamAttributes attributes = xml.attributes();
|
||||
|
||||
if (!attributes.hasAttribute(QStringLiteral("type")))
|
||||
return {};
|
||||
|
||||
Action *a = new Action();
|
||||
// set explicitely, as Action itself is "unset"
|
||||
a->aclass = AC_Standard;
|
||||
a->atype = static_cast<ActionType>(attributes.value(QStringLiteral("type")).toInt());
|
||||
if (attributes.hasAttribute(QStringLiteral("comment")))
|
||||
a->comment = attributes.value(QStringLiteral("comment")).toString();
|
||||
DEBUG_LOG(m_logger) << "--- parseStandardAction: Type: " << a->atype
|
||||
<< ", Comment: " << a->comment;
|
||||
DEBUG_LOG(m_logger) << "--- parseStandardAction End";
|
||||
return a;
|
||||
}
|
||||
|
||||
BsmAction *XmlReader::parseBsmAction(QXmlStreamReader &xml)
|
||||
{
|
||||
QXmlStreamAttributes attributes = xml.attributes();
|
||||
|
||||
|
||||
DEBUG_LOG(m_logger) << "--- parseBsmAction Start";
|
||||
BsmAction *a = new BsmAction();
|
||||
a->atype = static_cast<ActionType>(attributes.value(QStringLiteral("type")).toInt());
|
||||
if (attributes.hasAttribute(QStringLiteral("comment")))
|
||||
a->comment = attributes.value(QStringLiteral("comment")).toString();
|
||||
|
||||
xml.readNext();
|
||||
while (!(xml.tokenType() == QXmlStreamReader::EndElement &&
|
||||
xml.name() == QStringLiteral("bsm")))
|
||||
{
|
||||
// What about count?
|
||||
if (xml.name() == QStringLiteral("pause"))
|
||||
a->pause = xml.readElementText().toInt();
|
||||
if (xml.name() == QStringLiteral("choplength"))
|
||||
a->choplength = xml.readElementText().toInt();
|
||||
if (xml.name() == QStringLiteral("pulses"))
|
||||
a->pulses = xml.readElementText().toInt();
|
||||
if (xml.name() == QStringLiteral("pulseduration"))
|
||||
a->pulseduration = xml.readElementText().toInt();
|
||||
xml.readNext();
|
||||
}
|
||||
|
||||
DEBUG_LOG(m_logger) << "--- parseBsmAction: Type: " << a->atype
|
||||
<< ", Pause: " << a->pause
|
||||
<< ", Choplength: " << a->choplength
|
||||
<< ", Count: " << a->count
|
||||
<< ", Pulses: " << a->pulses
|
||||
<< ", Pulseduration: " << a->pulseduration
|
||||
<< ", Comment: " << a->comment;
|
||||
DEBUG_LOG(m_logger) << "--- parseBsmAction End";
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void XmlReader::createHttpRequests()
|
||||
{
|
||||
for (const Effect *e : m_contents.constEffects())
|
||||
{
|
||||
for (const Range *r : e->constRanges())
|
||||
{
|
||||
generateUrls(e, r->actions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QUrl XmlReader::createPreparedUrl(const XmlContents &contents, const QString &hostname)
|
||||
{
|
||||
QUrl url;
|
||||
url.setScheme(QStringLiteral("http"));
|
||||
url.setUserName(contents.username);
|
||||
url.setPassword(contents.password);
|
||||
if (!hostname.isEmpty())
|
||||
url.setHost(hostname);
|
||||
url.setPort(contents.port);
|
||||
return url;
|
||||
}
|
||||
|
||||
void XmlReader::generateUrl(const Effect *e, Action *a)
|
||||
{
|
||||
switch (a->aclass)
|
||||
{
|
||||
case AC_Standard:
|
||||
{
|
||||
QUrl url = createPreparedUrl(m_contents);
|
||||
QUrlQuery query;
|
||||
|
||||
switch (e->effectType)
|
||||
{
|
||||
case ET_Relay:
|
||||
{
|
||||
url.setPath(QStringLiteral("/relay.php"));
|
||||
query.addQueryItem(QStringLiteral("state"), QString::number(a->atype));
|
||||
query.addQueryItem(QStringLiteral("number"), QString::number(e->id));
|
||||
break;
|
||||
}
|
||||
case ET_BackgroundSound:
|
||||
{
|
||||
url.setPath(QStringLiteral("/bgsound.php"));
|
||||
query.addQueryItem(QStringLiteral("category"), categoryName(e->category));
|
||||
query.addQueryItem(QStringLiteral("sound"), QString::number(e->id));
|
||||
query.addQueryItem(QStringLiteral("vol"), QString::number(m_contents.bgSoundVolume));
|
||||
switch (a->atype)
|
||||
{
|
||||
case AT_Off:
|
||||
query.addQueryItem(QStringLiteral("control"), QStringLiteral("2"));
|
||||
break;
|
||||
case AT_On:
|
||||
query.addQueryItem(QStringLiteral("control"), QStringLiteral("1"));
|
||||
break;
|
||||
case AT_Infinite:
|
||||
query.addQueryItem(QStringLiteral("control"), QStringLiteral("3"));
|
||||
break;
|
||||
case AT_Flash:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
url.setQuery(query);
|
||||
a->url = url;
|
||||
DEBUG_LOG(m_logger) << "Effect " << e->name << ", Action '" << a->comment << "' now has URL: " << url.toString();
|
||||
break;
|
||||
}
|
||||
case AC_Repeat:
|
||||
{
|
||||
const RepeatAction *ra = static_cast<const RepeatAction *>(a);
|
||||
generateUrls(e, ra->actions);
|
||||
break;
|
||||
}
|
||||
case AC_Unset:
|
||||
case AC_Pause:
|
||||
case AC_Bsm:
|
||||
default:
|
||||
DEBUG_LOG(m_logger) << "Effect " << e->name << ", Action '" << a->comment << "' of Type " << a->aclass << " needs no URL";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void XmlReader::generateUrls(const Effect *e, const QVector<Action *> &actions)
|
||||
{
|
||||
for (Action *a : actions)
|
||||
generateUrl(e,a);
|
||||
}
|
||||
|
||||
|
||||
//QVector<Action *> Effect::getActionsByRange(int damagePercent) const
|
||||
//{
|
||||
// for (const Range *r : ranges)
|
||||
// {
|
||||
// if (r->fits(damagePercent))
|
||||
// return r->actions;
|
||||
// }
|
||||
// return {};
|
||||
//}
|
||||
|
||||
Range* Effect::getRangeByDamagePercent(int damagePercent) const
|
||||
{
|
||||
for (Range *r : ranges)
|
||||
{
|
||||
if (r->fits(damagePercent))
|
||||
return r;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString XmlReader::categoryName(Category c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case CT_BGS_Bahnhof:
|
||||
return QStringLiteral("bahnhof");
|
||||
case CT_BGS_Personen:
|
||||
return QStringLiteral("personen");
|
||||
case CT_BGS_Sonstige:
|
||||
return QStringLiteral("sonstige");
|
||||
case CT_BGS_Stadt:
|
||||
return QStringLiteral("stadt");
|
||||
case CT_BGS_Testsounds:
|
||||
return QStringLiteral("testsounds");
|
||||
case CT_BGS_Aircrafts:
|
||||
return QStringLiteral("Aircrafts");
|
||||
case CT_BGS_Battlefields:
|
||||
return QStringLiteral("Battlefields");
|
||||
case CT_BGS_Boats:
|
||||
return QStringLiteral("Boats");
|
||||
case CT_BGS_Explosions:
|
||||
return QStringLiteral("Explosions");
|
||||
case CT_BGS_Helicopter:
|
||||
return QStringLiteral("Helicopter");
|
||||
case CT_BGS_Motors_and_urban_traffic:
|
||||
return QStringLiteral("Motors_and_urban_traffic");
|
||||
case CT_BGS_InsideBuildings:
|
||||
return QStringLiteral("Inside_buildings");
|
||||
case CT_BGS_Vehicles:
|
||||
return QStringLiteral("Vehicles");
|
||||
case CT_Default:
|
||||
default:
|
||||
return QStringLiteral("Default");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // BuildingControlUnit
|
||||
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Xml Reader for Effect Configuration
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Gerlinde Rudolphus, SLTE, 2021-06-02
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include <ControlEffects/controleffects_export.h>
|
||||
|
||||
//#include <logger.h>
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
#include <QXmlStreamReader>
|
||||
#include <QVector>
|
||||
#include <QUrl>
|
||||
|
||||
namespace BuildingControlUnit
|
||||
{
|
||||
|
||||
class HandelEffect;
|
||||
|
||||
enum EffectType
|
||||
{
|
||||
// Keep in sync with EffectType from bcu_types.h
|
||||
ET_Unset = 0,
|
||||
ET_Relay = 1, // EGCU
|
||||
ET_BackgroundSound = 2, // EGCU
|
||||
ET_BsmFlash = 3, // BSM
|
||||
};
|
||||
|
||||
enum EffectOverride
|
||||
{
|
||||
EO_Auto = -1,
|
||||
EO_Off = 0,
|
||||
EO_On = 1,
|
||||
};
|
||||
|
||||
enum ActionType
|
||||
{
|
||||
AT_Off = 0,
|
||||
AT_On = 1,
|
||||
AT_Infinite = 2,
|
||||
AT_Flash = 3
|
||||
};
|
||||
|
||||
enum ActionClass
|
||||
{
|
||||
AC_Unset,
|
||||
AC_Standard,
|
||||
AC_Repeat,
|
||||
AC_Pause,
|
||||
AC_Bsm
|
||||
};
|
||||
|
||||
enum Category
|
||||
{
|
||||
CT_Default = 0,
|
||||
CT_BGS_Bahnhof = 1,
|
||||
CT_BGS_Personen = 2,
|
||||
CT_BGS_Sonstige = 3,
|
||||
CT_BGS_Stadt = 4,
|
||||
CT_BGS_Testsounds = 5,
|
||||
CT_BGS_Aircrafts = 6,
|
||||
CT_BGS_Battlefields = 7,
|
||||
CT_BGS_Boats = 8,
|
||||
CT_BGS_Explosions = 9,
|
||||
CT_BGS_Helicopter = 10,
|
||||
CT_BGS_Motors_and_urban_traffic = 11,
|
||||
CT_BGS_InsideBuildings = 12,
|
||||
CT_BGS_Vehicles = 13
|
||||
// CT_RL_Testkategorie = 8 geht auch (RL=Relay): Dann kann man beide Namen je nach EffectType verwenden!
|
||||
};
|
||||
|
||||
class Action
|
||||
{
|
||||
public:
|
||||
Action(ActionClass ac = AC_Unset)
|
||||
: aclass(ac)
|
||||
{}
|
||||
|
||||
ActionClass aclass = AC_Unset;
|
||||
ActionType atype = AT_Off;
|
||||
QUrl url;
|
||||
QString comment;
|
||||
};
|
||||
|
||||
class RepeatAction : public Action
|
||||
{
|
||||
public:
|
||||
RepeatAction()
|
||||
: Action(AC_Repeat)
|
||||
{}
|
||||
|
||||
// -1 => Infinite. So we can skip on (count == 0) in HandelEffect.
|
||||
int count = -1;
|
||||
QVector<Action *> actions;
|
||||
};
|
||||
|
||||
class PauseAction : public Action
|
||||
{
|
||||
public:
|
||||
PauseAction()
|
||||
: Action(AC_Pause)
|
||||
{}
|
||||
|
||||
int pause = 0;
|
||||
};
|
||||
|
||||
class BsmAction : public Action
|
||||
{
|
||||
public:
|
||||
bool isNull() const { return (count == 0 && pause == 0 && pulses == 0); }// Should be enough...
|
||||
int count = 0;
|
||||
int pause = 0;
|
||||
int choplength = 0;
|
||||
int pulses = 0;
|
||||
int pulseduration = 0;
|
||||
BsmAction() : Action(AC_Bsm) {}
|
||||
};
|
||||
|
||||
class Range
|
||||
{
|
||||
public:
|
||||
inline bool fits(int value) const { return (min <= value && value <= max); }
|
||||
|
||||
int min = 0;
|
||||
int max = 100;
|
||||
bool restartOnChange = false;
|
||||
QVector<Action *> actions;
|
||||
};
|
||||
|
||||
class Effect
|
||||
{
|
||||
public:
|
||||
// QVector<Action *> getActionsByRange(int damagePercent) const;
|
||||
Range* getRangeByDamagePercent(int damagePercent) const;
|
||||
|
||||
EffectType effectType = ET_Unset;
|
||||
Category category = CT_Default;
|
||||
int id = 0;
|
||||
QString name;
|
||||
QVector<Range *> ranges;
|
||||
HandelEffect *effectHandler = nullptr;
|
||||
EffectOverride override = EO_Auto;
|
||||
|
||||
const QVector<Range *> constRanges() const { return ranges; }
|
||||
};
|
||||
|
||||
struct XmlContents
|
||||
{
|
||||
QVector<Effect *> effects;
|
||||
int hitSoundVolume = 50;
|
||||
|
||||
int bgSoundVolume = 50;
|
||||
QString username;
|
||||
QString password;
|
||||
int port = 80;
|
||||
int updateRelayState = 1000;
|
||||
|
||||
const QVector<Effect *> constEffects() const { return effects; }
|
||||
|
||||
QString toString() const
|
||||
{
|
||||
QString str(QStringLiteral("User: %1, Password: %2, Port: %3, BGSound Vol: %4, HitSound Vol: %5, No of Effects: %6"));
|
||||
return str.arg(username, password).arg(port).arg(bgSoundVolume).arg(hitSoundVolume).arg(effects.count());
|
||||
}
|
||||
};
|
||||
|
||||
class XmlReader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit XmlReader(QObject *parent = nullptr);
|
||||
~XmlReader() = default;
|
||||
|
||||
static QUrl createPreparedUrl(const XmlContents &contents, const QString &hostname = QString());
|
||||
|
||||
bool init(const QString &effectConfigFile);
|
||||
XmlContents contents() const { return m_contents; }
|
||||
|
||||
private:
|
||||
void createHttpRequests();
|
||||
static QString categoryName(Category c);
|
||||
|
||||
Effect *parseEffect(QXmlStreamReader &xml);
|
||||
Range *parseRange(QXmlStreamReader &xml);
|
||||
Action *parseAction(QXmlStreamReader &xml);
|
||||
PauseAction *parsePauseAction(QXmlStreamReader &xml);
|
||||
RepeatAction *parseRepeatAction(QXmlStreamReader &xml);
|
||||
BsmAction* parseBsmAction(QXmlStreamReader &xml);
|
||||
Action *parseStandardAction(QXmlStreamReader &xml); // Can be BsmAction or Action alone
|
||||
|
||||
void generateUrls(const Effect *e, const QVector<Action *> &actions);
|
||||
void generateUrl(const Effect *e, Action *a);
|
||||
|
||||
XmlContents m_contents;
|
||||
//BuildingControlUnit::LOGGER_T m_logger;
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
};
|
||||
|
||||
} // BuildingControlUnit
|
||||
Reference in new issue
Block a user