/** * @RDE_HEADER@ * main for BuildingControlUnit * $Id$ * $HeadURL$ * $Author$ * Created by Christian Ehrlicher, SLSE, 2017-01-27 */ #include "main_handler.h" #include #include "VWM/vwm_types.h" #include "bcu_xml_reader.h" #include #include "ControlEffects/xmlreader.h" namespace BuildingControlUnit { MainHandler::MainHandler() : QObject() , m_bsmApi(nullptr) , m_jsonApi(nullptr) , m_vwmApi(nullptr) , m_handelEffectsBsm(nullptr) , m_handleHttpRequest(nullptr) , m_bsmFlash(BEO_Auto) , m_logger(getLogger("MainHandler")) {} MainHandler::~MainHandler() { cleanup(); } bool MainHandler::init(const QString &ammuXml, const QString &bldCfgXml, const QString &vwmXml, unsigned short listenPort, const bool initBuilding, const QString &controlEffectsCfg) { NOTICE_LOG(m_logger) << "----------------------------------------------------"; NOTICE_LOG(m_logger) << "-- start BuildingControlUnit --"; NOTICE_LOG(m_logger) << "----------------------------------------------------"; cleanup(); BuildingBsmConfig bsmConfig; if (!parseBuildingConfigXml(bldCfgXml, bsmConfig, m_egcuConfig)) return false; m_bsmApi = new BSM::Api(this); //m_egcuApi = new EGCU::Api(this); m_jsonApi = new Json::Api(this); m_vwmApi = new VWM::Api(this); m_handleHttpRequest = new HandleHttpRequest(Settings::useHttpQueue(), this); m_bsmFlash = BEO_Auto; if (m_egcuConfig.egcus.size() == 1 && m_egcuConfig.egcus.first().roomIds.isEmpty()) { auto &egcu = m_egcuConfig.egcus.first(); const auto &bldg = m_vwmApi->building(); m_egcuConfig.egcus.reserve(bldg.rooms().size()); for (const auto &room : bldg.rooms()) egcu.roomIds.append(room.id()); } if (!m_vwmApi->init(ammuXml, vwmXml, bsmConfig, initBuilding)) { ERROR_LOG(m_logger) << "Can not initialize VWM API - aborting"; return false; } if (!m_jsonApi->init(listenPort)) { ERROR_LOG(m_logger) << "Can not initialize Json API - aborting"; return false; } if (!m_bsmApi->init(bsmConfig)) { ERROR_LOG(m_logger) << "Can not initialize BSM API - aborting"; return false; } m_handelEffectsVec.clear(); for ( int i = 0; i < m_egcuConfig.egcus.size(); i++) { NOTICE_LOG(m_logger) << "new BuildingControlUnit::HandelEffects " << m_egcuConfig.egcus[i].hostname; BuildingControlUnit::HandelEffects *handleEffectsEgcu = new BuildingControlUnit::HandelEffects(this, m_egcuConfig.egcus[i].hostname); handleEffectsEgcu->init(controlEffectsCfg, m_egcuConfig.egcus[i].hostname, ET_Relay); connect(handleEffectsEgcu, &HandelEffects::newHttpRequest, m_handleHttpRequest, &HandleHttpRequest::enqueue); connect(handleEffectsEgcu, &HandelEffects::sendRelayState, m_jsonApi, &Json::Api::onRelayState); connect(m_handleHttpRequest, &HandleHttpRequest::egcuReply, handleEffectsEgcu, &HandelEffects::handleEgcuReply); //connect(m_handleHttpRequest, &HandleHttpRequest::newEgcuConnection, this, &MainHandler::setInitialOverrides); m_handelEffectsVec.append(handleEffectsEgcu); } m_handelEffectsBsm = new BuildingControlUnit::HandelEffects(this, QStringLiteral("BSMs")); m_handelEffectsBsm->init(controlEffectsCfg, QString(), ET_BsmFlash); connect(m_handelEffectsBsm, &HandelEffects::triggerAllFlashlights, m_bsmApi, &BSM::Api::triggerFlashlights); connect(m_bsmApi, &BSM::Api::opticalShot, m_vwmApi, &VWM::Api::onHitOptical); connect(m_bsmApi, &BSM::Api::opticalShotOC, m_vwmApi, &VWM::Api::onHitOpticalOC); connect(m_vwmApi, &VWM::Api::hitResult, this, &MainHandler::onHitResult); connect(m_vwmApi, &VWM::Api::unknownDirectHit, this, &MainHandler::onUnknownDirectHit); connect(m_jsonApi, &Json::Api::damageStateRequest, m_vwmApi, &VWM::Api::onHitEcc); connect(m_jsonApi, &Json::Api::setContaminationStateRequest,m_vwmApi, &VWM::Api::onSetContaminationState); connect(m_jsonApi, &Json::Api::resetContaminationRequest, m_vwmApi, &VWM::Api::onResetContaminations); connect(m_jsonApi, &Json::Api::setFortifyFactorRequest, m_vwmApi, &VWM::Api::onFortifyFactorRequest); connect(m_jsonApi, &Json::Api::relayStatesRequest, m_vwmApi, &VWM::Api::onRelayStatesRequest); connect(m_jsonApi, &Json::Api::centralEffectSimulationHit, m_vwmApi, &VWM::Api::onHitCes); connect(m_jsonApi, &Json::Api::centralEffectSimulationHit3D,m_vwmApi, &VWM::Api::onHitCes3D_Evaluation); connect(m_jsonApi, &Json::Api::bsmTriggerFlashlightRequest, m_bsmApi, &BSM::Api::triggerFlashlight); connect(m_jsonApi, &Json::Api::getBsmConfiguration, m_bsmApi, &BSM::Api::getBsmConfiguration); connect(m_jsonApi, &Json::Api::getBsmBitTimeout, m_bsmApi, &BSM::Api::getBsmBitTimeout); connect(m_jsonApi, &Json::Api::getBsmTechnicalStatus, m_bsmApi, &BSM::Api::getBsmTechnicalStatus); // for debug purposes connect(m_jsonApi, &Json::Api::simulateBSMHit, m_vwmApi, &VWM::Api::onHitOptical); connect(m_jsonApi, &Json::Api::setEffectStatesRequest, m_vwmApi, &VWM::Api::onSetEffectStatesRequest); connect(m_bsmApi, &BSM::Api::bsmStateChanged, m_jsonApi, &Json::Api::onBsmState); connect(m_vwmApi, &VWM::Api::hitResult, m_jsonApi, &Json::Api::onHitResult); connect(m_jsonApi, &Json::Api::webSocketConnected, this, &MainHandler::webSocketSendInitialData); connect(m_jsonApi, &Json::Api::setEffectStatesRequest, this, &MainHandler::onSetEffectStatesRequest); connect(m_jsonApi, &Json::Api::switchRelayRequest, this, &MainHandler::onSwitchRelayRequest); connect(m_vwmApi, &VWM::Api::newOverrides, this, &MainHandler::onSetEffectStatesRequest); m_vwmApi->sendOverrides(); onHitResult(m_vwmApi->lastHitResult(), m_vwmApi->contaminationStates(), false); // Set initial Overrides: //setInitialOverrides(); return true; } void MainHandler::setInitialOverrides(const QString &hostname) { DEBUG_LOG(m_logger) << "setInitialOverrides m_handelEffectsVec.size()=" << m_handelEffectsVec.size(); // Set initial Overrides: for ( int i = 0; i < m_handelEffectsVec.size(); i++) { QString hostnameLocal = m_handelEffectsVec.at(i)->hostname(); const QVector effectStates = m_handelEffectsVec.at(i)->getOverrides(); DEBUG_LOG(m_logger) << "setInitialOverrides host=" << hostnameLocal << " effectStates.size=" << effectStates.size(); for (int j = 0; j < effectStates.size(); j++) DEBUG_LOG(m_logger) << "setInitialOverrides j=" << j << " id=" << effectStates[j].id << " type=" << effectStates[j].type << " override=" << effectStates[j].effectOverride; NOTICE_LOG(m_logger) << "'" << hostname << "'" << " '" << hostnameLocal << "'"; if ( hostname.toLower() == hostnameLocal.toLower()) { onSetEffectStatesRequest(hostnameLocal, effectStates); const QString segment = hostname ; const qint64 stateTime = QDateTime::currentMSecsSinceEpoch();; const qint64 offlineTime = QDateTime::currentMSecsSinceEpoch(); m_jsonApi->sendEffectOverrides(segment, stateTime, offlineTime, effectStates, nullptr); } } } void MainHandler::onHitResult(const HitResult &result, const QMap &contaminationStates, bool playSound) { Q_UNUSED(contaminationStates) const VWM::Charge charge = m_vwmApi->chargeFromChargeTypeId(result.chargeTypeId); DEBUG_LOG(m_logger) << "onHitResult chargeTypeId=" << result.chargeTypeId << " result.effectSoundId=" << result.effectSoundId << " damagePercentNew=" << result.damagePercentNew << " destructiveFactor=" << charge.destructiveFactor; if (Settings::laserRangeCode() == result.chargeTypeId) return; if (playSound) { for (HandelEffects *he : qAsConst(m_handelEffectsVec)) { DEBUG_LOG(m_logger) << "playHitSound @EGCU " << he->hostname() << ", SoundId: " << result.effectSoundId; he->playHitSound(result.effectSoundId); } } DEBUG_LOG(m_logger) << "HitResult: " << result; if (result.sensorId != 0 && result.originatorId != 0 && m_bsmFlash != BEO_Off && charge.destructiveFactor > 1 ) { DEBUG_LOG(m_logger) << "BSM Flash"; m_bsmApi->triggerFlashlight(result.sensorId); m_bsmApi->triggerFlashlightPulse(result.sensorId, // ??? Woher kommt der Hostname? Es blitzt ja bei trigger Flashlight Patric: Wenn Hosname Leer ist ruft er die Funktion getSocketForBsm auf QString(), Settings::numberOfFlashes(), Settings::pauseDuration(), Settings::choppedConfiguration(), Settings::flashDuration()); } else DEBUG_LOG(m_logger) << "Kein BSM Flash"; // only once on state change (to not trigger it more than once) //if (result.damagePercentOld < Settings::fireThreshold() && // result.damagePercentNew > Settings::fireThreshold()) // Each Segment QVector segmentDamage = getSegmentDamage(result.rooms, result.damagePercentNew); for (int i = 0; i < m_egcuConfig.egcus.size(); i++) { DEBUG_LOG(m_logger) << "segmentDamage.size=" << segmentDamage.size(); if ( i < segmentDamage.size() ) { DEBUG_LOG(m_logger) << "segmentDamage[" << i <<"]=" << segmentDamage[i]; m_handelEffectsVec[i]->startEffects(segmentDamage[i]); } else DEBUG_LOG(m_logger) << "No segment Damage for egcu:" << m_egcuConfig.egcus[i].hostname; } m_handelEffectsBsm->startEffects(result.damagePercentNew); } void MainHandler::onUnknownDirectHit(int sensorId) { // unknown dus code - double flash m_bsmApi->triggerFlashlight(sensorId); m_bsmApi->triggerFlashlight(sensorId); } void MainHandler::onSetEffectStatesRequest(const QString &hostname, const QVector &effectStates) { DEBUG_LOG(m_logger) << "1 BSM flash hostname='" << hostname << "' isEmpty:"<< hostname.isEmpty() <<" isNull:" << hostname.isNull(); m_effectStates.insert(hostname, effectStates); if (hostname.isEmpty()) { m_bsmFlash = BEO_Auto; DEBUG_LOG(m_logger) << "2 BSM flash =" << m_bsmFlash; m_handelEffectsBsm->setOverrides(effectStates); for ( int i = 0; i < effectStates.size(); i++) { DEBUG_LOG(m_logger) << "3 BSM flash =" << m_bsmFlash; if ( effectStates.at(i).type == BET_BsmFlash) { m_bsmFlash = effectStates.at(i).effectOverride; DEBUG_LOG(m_logger) << "4 BSM flash =" << m_bsmFlash; break; } } return; } for (HandelEffects* hes : qAsConst(m_handelEffectsVec)) { if (hes->hostname() != hostname) continue; hes->setOverrides(effectStates); } } void MainHandler::onSwitchRelayRequest(const QString &hostname, const SwitchRelayValues &switchRelayValues) { for ( int i = 0; i < m_handelEffectsVec.size(); i++) { if (m_handelEffectsVec[i]->hostname() == hostname ) { DEBUG_LOG(m_logger) << "switchRelay " << " id=" << switchRelayValues.id << " bcuRelayState=" << switchRelayValues.bcuRelayState; m_handelEffectsVec[i]->switchRelay(switchRelayValues); } } } void MainHandler::webSocketSendInitialData(QWebSocket *ws) { m_jsonApi->sendBsmState(m_bsmApi->bsmStates(), ws); m_jsonApi->sendHitResult(m_vwmApi->lastHitResult(), m_vwmApi->contaminationStates(), ws); } QVector MainHandler::getAffectedRoomIds(const QVector &allHitRooms) const { QVector ret; for (const HitRoom &hr : allHitRooms) { if (hr.remainingEffectPercent == 0) continue; ret += hr.roomId; } return ret; } int MainHandler::getHitRoomId(const QVector &allHitRooms) const { for (const HitRoom &hr : allHitRooms) { if (hr.directHit) return hr.roomId; } return 0; } QVector MainHandler::getSegmentDamage(const QVector &allHitRooms, const int damagePercentNew) const { QVector result; if (m_egcuConfig.egcus.size() == 0) return result; result.reserve(m_egcuConfig.egcus.size()); // every egcu is responsible for one segment for (const Egcu &egcu : qAsConst(m_egcuConfig.egcus)) { int damagePercentSegment = 0; for (const HitRoom &hr : allHitRooms) { if (egcu.roomIds.contains(hr.roomId)) damagePercentSegment += hr.damagePercent; } // Can only occur when roomIds.size() > 0 if (damagePercentNew == 0) result.append(0); else if (damagePercentNew == 100) result.append(100); else { int averageDamage = 0; if (egcu.roomIds.size() > 0 ) averageDamage = damagePercentSegment / egcu.roomIds.size(); result.append(averageDamage); INFO_LOG(m_logger) << "getSegmentDamage[" << egcu.hostname << "]=" << averageDamage; } } return result; } void MainHandler::flashBuildingDestructionIndicator(int egcu) { // Todo: What's this? ERROR_LOG(m_logger) << "TODO flashBuildingDestructionIndicator egcu=" << egcu; // Building Destruction Indicator //RelayHardwareConfig hwCfg; // TODO Config TBD //hwCfg.cntRepeat = 0; //hwCfg.damage = 100; //hwCfg.durationDelay = 0; //hwCfg.durationPulses = 500; //hwCfg.relayNumber = 0; //m_egcuApi->startHardware(hwCfg, egcu); } void MainHandler::cleanup() { delete m_bsmApi; //delete m_egcuApi; delete m_jsonApi; delete m_vwmApi; } } // BuildingControlUnit