/** * Retrieve data from InfrastructeManagement * $Id$ * $HeadURL$ * $Author$ * Created by Christian Ehrlicher, SLSE, 2016-04-14 */ #include "ism_handler.h" #include "main_handler.h" #include #include #include #include #include #include #include #include namespace Buildings { IsmHandler::IsmHandler(MainHandler *mainHandler) : m_mainHandler(mainHandler) , m_dtcIsm(nullptr) , m_ftcIsm(nullptr) , m_changeTimeoutTimer(new QTimer(this)) , m_changeTimeoutTimerInit(new QTimer(this)) , m_logger(getLogger("IsmHandler")) { connect(m_changeTimeoutTimer, &QTimer::timeout, this, &IsmHandler::onBuildingsChanged); m_changeTimeoutTimer->setInterval(3 * 1000); m_changeTimeoutTimer->setSingleShot(true); connect(m_changeTimeoutTimerInit, &QTimer::timeout, this, &IsmHandler::onBuildingsChangedInit); m_changeTimeoutTimerInit->setInterval(3 * 1000); m_changeTimeoutTimerInit->setSingleShot(true); } IsmHandler::~IsmHandler() {} bool IsmHandler::init() { if (m_dtcIsm) return true; m_dtcIsm = InfrastructureManagement::Interface::Dtc::create(m_mainHandler->ddsHandler()->ddsConnector()); connect(m_dtcIsm.get(), &InfrastructureManagement::Interface::Dtc::instrumentationAssetChanged, this, &IsmHandler::onInstrumentationAssetChanged); connect(m_dtcIsm.get(), &InfrastructureManagement::Interface::Dtc::mountingPointAssetChanged, this, &IsmHandler::onMountingPointAssetChanged); connect(m_dtcIsm.get(), &InfrastructureManagement::Interface::Dtc::mainStructureElementChanged, this, &IsmHandler::onMainStructureElementChanged); connect(m_dtcIsm.get(), &InfrastructureManagement::Interface::Dtc::bridgeChangeStatusChanged, this, &IsmHandler::onBridgeStatusChanged); if (!m_dtcIsm->enableInstrumentationAsset() || !m_dtcIsm->enableMainStructureElement() || !m_dtcIsm->enableMountingPointAsset() || !m_dtcIsm->enableBridgeChangeStatus()) { ERROR_LOG(m_logger) << "Can not read data from ISM"; return false; } m_ftcIsm = InfrastructureManagement::Interface::Ftc::create(m_mainHandler->ddsHandler()->ddsConnector()); if (!m_ftcIsm->enableStructureElementUpdateEffectOverride()) { ERROR_LOG(m_logger) << "Can not read data from ISM"; return false; } m_changeTimeoutTimerInit->start(); return true; } bool IsmHandler::isElementAssignedToExercise(const int mseId, int exerciseId) { InfrastructureManagement::MainStructureElement mse = m_dtcIsm->mainStructureElement(mseId); return m_dtcIsm->isElementAssignedToExercise(mse, exerciseId); } void IsmHandler::onInstrumentationAssetChanged(const InfrastructureManagement::InstrumentationAsset &data, DataModification modType) { // no need for other assets ... if (data.mountingPointTypeId() == InfrastructureManagement::MountingPointType::BuildingSensorModule || data.mountingPointTypeId() == InfrastructureManagement::MountingPointType::EffectGenerationControlUnit) { switch (modType) { case DataModification::eAdded: case DataModification::eModified: m_instAssets.insert(data.id(), data); break; case DataModification::eRemoved: m_instAssets.remove(data.id()); break; } m_changeTimeoutTimer->start(); return; } if (data.mountingPointTypeId() == InfrastructureManagement::MountingPointType::BuildingControlUnit) { switch (modType) { case DataModification::eAdded: case DataModification::eModified: { const int exerciseId = data.availableInExercise().size() == 0 ? 0 : data.availableInExercise().at(0); DEBUG_LOG(m_logger) << "setting asset " << data.id() << " available in exercise " << exerciseId; m_assetMainStructureElementInExercise.insert(data.id(), exerciseId); break; } case DataModification::eRemoved: { const int exerciseId = data.availableInExercise().size() == 0 ? 0 : data.availableInExercise().at(0); DEBUG_LOG(m_logger) << "removing asset " << data.id() << " from exercise " << exerciseId; m_assetMainStructureElementInExercise.remove(data.id()); break; } } m_changeTimeoutTimer->start(); } } void IsmHandler::onMountingPointAssetChanged(const InfrastructureManagement::MountingPointAsset &data, DataModification modType) { switch (modType) { case DataModification::eAdded: case DataModification::eModified: DEBUG_LOG(m_logger) << "mounting asset " << data.assetId() << " on structure element id " << data.structureElementId(); m_structureElementId2AssetId.insert(data.structureElementId(), data.assetId()); break; case DataModification::eRemoved: DEBUG_LOG(m_logger) << "unmounting asset " << m_structureElementId2AssetId.value(data.structureElementId()) << " from structure element " << data.structureElementId(); m_structureElementId2AssetId.remove(data.structureElementId()); break; } m_changeTimeoutTimer->start(); } void IsmHandler::onMainStructureElementChanged(const InfrastructureManagement::MainStructureElement &data, DataModification modType) { DEBUG_LOG(m_logger) << LOGFUNCTION; switch (modType) { case DataModification::eAdded: case DataModification::eModified: { if (!isElementAssignedToExercise (data.id(),m_mainHandler->exerciseId() ) ) { m_mainStructureElements.remove(data.id()); DEBUG_LOG(m_logger) << "Building not in exercise id=" << data.id(); return; } DEBUG_LOG(m_logger) << "Building=" << data.name() << " properties=" << data.properties(); QJsonParseError parserError; QByteArray content = QByteArray::fromStdString(data.properties()); const QJsonDocument doc(QJsonDocument::fromJson(content, &parserError)); if (parserError.error != QJsonParseError::NoError) { WARNING_LOG(m_logger) << "Error parsing json document: " << parserError.errorString(); return; } DEBUG_LOG(m_logger) << "json to parse: " << doc.toJson(); const QJsonObject objProperties(doc.object()); if ( objProperties.contains(QStringLiteral("start_building_process"))) { DEBUG_LOG(m_logger) << "properties contains start_building_process"; bool startBuildingProcess = objProperties.value(QStringLiteral("start_building_process")).toBool(); if (!startBuildingProcess) { DEBUG_LOG(m_logger) << "Building=" << data.name() << " start_building_process = false "; return; } } DEBUG_LOG(m_logger) << "##### onMainStructureElementChanged - ID = " << data.id(); checkOverride( m_mainStructureElements[data.id()], data); m_mainStructureElements[data.id()] = data; break; } case DataModification::eRemoved: m_mainStructureElements.remove(data.id()); break; } m_changeTimeoutTimer->start(); } void IsmHandler::onBridgeStatusChanged(const InfrastructureManagement::BridgeChangeStatus &data, DataModification modType) { static int s_id = 1; DEBUG_LOG(m_logger) << LOGFUNCTION << "s_id=" << s_id; switch (modType) { case DataModification::eAdded: case DataModification::eModified: { DEBUG_LOG(m_logger) << "##### onBridgeStatusChanged - buildingId = " << data.buildingId(); BridgeStatus bs; bs.id(s_id++); // irrelevant bs.buildingId(data.buildingId()); bs.sampleTime(data.sampleTime()); bs.status(m_dtcIsm->getBridgeStatus(data.buildingId()).underlying()); m_mainHandler->ddsHandler()->dts()->publish(bs); break; } case DataModification::eRemoved: break; } m_changeTimeoutTimer->start(); } void IsmHandler::getEgcuToRoom(const InfrastructureManagement::MainStructureElement &mse, QVector &eis) { INFO_LOG(m_logger) << "properties=" << mse.properties(); QJsonParseError parserError; QByteArray content = QByteArray::fromStdString(mse.properties()); const QJsonDocument doc(QJsonDocument::fromJson(content, &parserError)); if (parserError.error != QJsonParseError::NoError) { WARNING_LOG(m_logger) << "Error parsing json document: " << parserError.errorString(); return; } DEBUG_LOG(m_logger) << "json to parse: " << doc.toJson(); const QJsonObject objEgcus(doc.object()); const QJsonArray arrEgcus(objEgcus.value(QStringLiteral("egcusToRooms")).toArray()); for (int i = 0; i < arrEgcus.size(); ++i) { //Egcu egcu; const QJsonObject objRooms(arrEgcus.at(i).toObject()); const int mountpointEgcuId = objRooms[QStringLiteral("mountpointEgcu")].toInt(); INFO_LOG(m_logger) << "mountpointEgcu=" << mountpointEgcuId; INFO_LOG(m_logger) << "i=" <exerciseId() != bi.currentExerciseId) { DEBUG_LOG(m_logger) << "Exercise id of building does not match current exercise: " << bi.currentExerciseId << " != " << m_mainHandler->exerciseId() << " buildingId=" << bi.mseId << " buildingName" << bi.name; continue; } INFO_LOG(m_logger) << "Adding building configuration for " << mse.id() << " - " << mse.name(); availableBuildingIds += mse.id(); getEgcuToRoom(mse, bi.egcus); newBuildingConfiguration.insert(bi.mseId, bi); } for (auto it = m_currentBuildingConfiguration.begin(); it != m_currentBuildingConfiguration.end(); ++it) { const int buildingId = it.key(); if (!availableBuildingIds.contains(buildingId)) { // Building wurde gelöscht -> entfernen INFO_LOG(m_logger) << "Building " << buildingId << " no longer exists in this exercise - removing"; emit buildingRemoved(buildingId); continue; } const BuildingInfo &biOld = it.value(); const BuildingInfo &biNew = newBuildingConfiguration.value(buildingId); if (biOld == biNew) { INFO_LOG(m_logger) << "Building " << buildingId << " did not change - nothing to do"; } else { INFO_LOG(m_logger) << "setHistoryState Building " << buildingId << " changed -> updating configuration" << " biNew mseId=" << biNew.mseId << " init=" << init; bool initBuildingChanged = true; emit buildingChanged(biNew, initBuildingChanged); } } for (auto it = newBuildingConfiguration.begin(); it != newBuildingConfiguration.end(); ++it) { if (m_currentBuildingConfiguration.contains(it.key())) continue; INFO_LOG(m_logger) << "setHistoryState New building added key= " << it.key() << " init=" << init; emit buildingChanged(it.value(), init); } m_currentBuildingConfiguration = newBuildingConfiguration; } void IsmHandler::handleBuildingSensorModule(const InfrastructureManagement::StructureElement &se, BuildingInfo &bi) const { auto itMpa = m_structureElementId2AssetId.find(se.id()); if (itMpa == m_structureElementId2AssetId.end()) return; const int assetId = itMpa.value(); const auto itAsset = m_instAssets.find(assetId); if (itAsset == m_instAssets.end()) return; const InfrastructureManagement::InstrumentationAsset &ia = itAsset.value(); BsmInfo bsi; bsi.assetId = assetId; bsi.bsmId = se.mountingPointId(); bsi.hostname = QString::fromStdString(ia.hostname()); bsi.port = getBsmPortFromJSon(ia.properties()); bsi.relPosition = se.relPosition(); bsi.orientation = se.orientation(); DEBUG_LOG(m_logger) << "adding bsm sensor module to building " << bi.mseId << ": " << bsi.assetId << ", " << bsi.bsmId << ", " << bsi.hostname; bi.bsms.insert(bsi.assetId, bsi); } void IsmHandler::handleBuildingControlUnit(const InfrastructureManagement::StructureElement &se, BuildingInfo &bi) const { bi.currentExerciseId = 0; // cfroebel 2018-11-28: // Why so complicated? The information about the assignment of a Building to an Exercise is part of // the MainStructureElement itself (e.g. properties = {"available_in_exercise": [42]}). // There is no need to retrieve this information from the mounted Asset. auto itMpa = m_structureElementId2AssetId.find(se.id()); if (itMpa == m_structureElementId2AssetId.end()) { INFO_LOG(m_logger) << "structure element id " << se.id() << " not (yet)found" << " bi.mseId=" << bi.mseId << " bi.assetId=" << bi.assetId << " bi.egcus.size=" << bi.egcus.size() << " bi.roomName2RoomId.size()=" << bi.roomName2RoomId.size(); return; } const int assetId = itMpa.value(); const auto itAsset = m_assetMainStructureElementInExercise.find(assetId); if (itAsset == m_assetMainStructureElementInExercise.end()) { ERROR_LOG(m_logger) << "asset id " << assetId << " not found"; Q_ASSERT(false); return; } bi.currentExerciseId = itAsset.value(); bi.assetId = itAsset.key(); DEBUG_LOG(m_logger) << "adding bsm control unit (virtual) to building " << bi.mseId << ": " << bi.assetId << ", " << bi.currentExerciseId; } void IsmHandler::handleEffectGenerationControlUnit(const InfrastructureManagement::StructureElement &se, BuildingInfo &bi) const { DEBUG_LOG(m_logger) << "BuildingId=" << bi.mseId << " se.id=" << se.id(); auto itMpa = m_structureElementId2AssetId.find(se.id()); if (itMpa == m_structureElementId2AssetId.end()) { INFO_LOG(m_logger) << "Return m_structureElementId2AssetId.size()=" << m_structureElementId2AssetId.size(); return; } const int assetId = itMpa.value(); const auto itAsset = m_instAssets.find(assetId); if (itAsset == m_instAssets.end()) { INFO_LOG(m_logger) << "Return m_instAssets.size()=" << m_instAssets.size(); return; } const InfrastructureManagement::InstrumentationAsset &ia = itAsset.value(); EgcuInfo egcu; egcu.buildingName = bi.name; egcu.mountPointName = QString::fromStdString(se.name()); egcu.mountPointId = se.mountingPointId(); egcu.hostname = QString::fromStdString(ia.hostname()); egcu.assetId = assetId; DEBUG_LOG(m_logger) << "Egcu.hostname=" << egcu.hostname; INFO_LOG(m_logger) << "properties=" << ia.properties(); bi.egcus.push_back(egcu); DEBUG_LOG(m_logger) << "adding egcu to building " << bi.mseId << ": " << egcu.hostname << " name=" << egcu.buildingName << " mountPointName=" << egcu.mountPointName << " mountPointId=" << egcu.mountPointId << " rooms.size=" << egcu.roomIds.size(); } unsigned short IsmHandler::getBsmPortFromJSon(const std::string &s) { // fallback, default is 12000 constexpr int s_defBsmPort = 12000; QJsonParseError jError; QJsonDocument doc(QJsonDocument::fromJson(s.c_str(), &jError)); if (jError.error != QJsonParseError::NoError || !doc.isObject()) { return s_defBsmPort; // default port } QJsonObject obj(doc.object()); int ret = obj[QStringLiteral("port")].toInt(); return ret ? ret : s_defBsmPort; } InfrastructureManagement::MainStructureElement IsmHandler::mainStructureElement(int id) const { return m_mainStructureElements.value(id); } void IsmHandler::checkOverride(const InfrastructureManagement::MainStructureElement &mseOld, const InfrastructureManagement::MainStructureElement &mseNew) { DEBUG_LOG(m_logger) << LOGFUNCTION; DEBUG_LOG(m_logger) << "mseOld.elements().size()=" << mseOld.elements().size() << " mseNew.elements().size()=" << mseNew.elements().size(); // if (mseOld.elements().size() != mseNew.elements().size()) // return; for (const InfrastructureManagement::StructureElement &se : mseNew.elements()) { DEBUG_LOG(m_logger) << "se=" << se.id() << " name=" << se.name() << " displayName=" << se.displayName() << " properties=" << se.properties(); for (const InfrastructureManagement::StructureElement &seOld : mseOld.elements()) { DEBUG_LOG(m_logger) << "seOld.id=" << seOld.id() << " se.id=" << se.id(); if ( seOld.id() == se.id()) { DEBUG_LOG(m_logger) << "Properties =" << se.properties() << " se.id=" << se.id() << " se.name=" << se.name() << " mountingPointId=" << se.mountingPointId(); DEBUG_LOG(m_logger) << "se.properties()=" << se.properties() << " seOld.properties()=" << seOld.properties(); if (se.properties() != seOld.properties() ) { DEBUG_LOG(m_logger) << "HandleOverrides" "<< m_currentBuildingConfiguration.size=" << m_currentBuildingConfiguration.size(); if ( se.structureElementTypeId() == InfrastructureManagement::StructureElementType::Building) // BSM-Flash, no EGCU { DEBUG_LOG(m_logger) << "BSM-Flash, no EGCU"; QByteArray properties = QByteArray::fromStdString(se.properties()); emit setEffectStates(mseNew.id(), 0, properties ); // 0 ist die AssetId, die nur fuer die Relais relevant ist. continue; } for (auto it = m_currentBuildingConfiguration.begin(); it != m_currentBuildingConfiguration.end(); ++it) { BuildingInfo &bi = it.value(); DEBUG_LOG(m_logger) << "key=" << it.key() << " id=" << bi.mseId << " assetId=" << bi.assetId << " egcus.size=" << bi.egcus.size(); for (const auto &egcu : qAsConst(bi.egcus)) { DEBUG_LOG(m_logger) << "AssetId=" << egcu.assetId << " assetName=" << egcu.assetName << " hostname=" << egcu.hostname << " egcu.mountPointId=" << egcu.mountPointId << " se.mountingPointId()=" << se.mountingPointId(); if (egcu.mountPointId == se.mountingPointId()) { QByteArray properties = QByteArray::fromStdString(se.properties()); DEBUG_LOG(m_logger) << "Send Json SetEffectStates to BuildingProcess" << " buildingId=" << " assetId="<< egcu.assetId << " properties =" << properties; emit setEffectStates(mseNew.id(), egcu.assetId, properties ); } } } } } else { TRACE_LOG(m_logger) << "No changes do not HandleOverrides"; } } // for // Only for Init Process: if (mseOld.elements().size() == 0) { QByteArray properties = QByteArray::fromStdString(se.properties()); QByteArray overrides("Overrides"); if (properties.contains(overrides)) { //int assetId = getEgcuAssetId(se.mountingPointId()); int assetId; bool foundAssetId = m_dtcIsm->getAssetIdFromMountingPoint(se.id(), se.mountingPointId(), assetId); DEBUG_LOG(m_logger) << "Send Overrides to BuildingProcess (EGCU)" << " foundAssetId=" << foundAssetId << " structureElementId=" << mseNew.id() << " se.id=" << se.id() << " mountingPointId=" << se.mountingPointId() << " assetId=" << assetId; emit setEffectStates(mseNew.id(), assetId, properties ); } } // End Only for Init Process: } // for } } // namespace Buildings