From 141ebab3da64aae573ac52ee25970ef0be3e1827 Mon Sep 17 00:00:00 2001 From: Alessio Netti Date: Fri, 13 Dec 2019 15:34:23 +0100 Subject: [PATCH] Analytics: added "isOperation" metadata field - Basic implementation that allows to publish sensors as operations of other sensors - Still not functional and untested --- .../includes/OperatorConfiguratorTemplate.h | 50 ++++++++++++------- common/include/metadatastore.h | 20 ++++++++ dcdbpusher/README.md | 1 + 3 files changed, 52 insertions(+), 19 deletions(-) diff --git a/analytics/includes/OperatorConfiguratorTemplate.h b/analytics/includes/OperatorConfiguratorTemplate.h index 477b003..25281d8 100644 --- a/analytics/includes/OperatorConfiguratorTemplate.h +++ b/analytics/includes/OperatorConfiguratorTemplate.h @@ -618,33 +618,45 @@ protected: * @return true if successful, false otherwise */ bool constructSensorTopics(UnitTemplate& u, Operator& op) { - std::string name; // Performing name construction for(auto& s: u.getOutputs()) { - s->setName(s->getMqtt()); - SensorMetadata* sm = s->getMetadata(); - if(sm) { - sm->publicName = s->getMqtt(); - sm->pattern = s->getMqtt(); - sm->isVirtual = false; - if(sm->interval==0) - sm->interval = (unsigned long long)op.getInterval() * 1000000; - } + adjustSensor(s, op, u); } for(auto& subUnit: u.getSubUnits()) for(auto& s : subUnit->getOutputs()) { - s->setName(s->getMqtt()); - SensorMetadata* sm = s->getMetadata(); - if(sm) { - sm->publicName = s->getMqtt(); - sm->pattern = s->getMqtt(); - sm->isVirtual = false; - if(sm->interval==0) - sm->interval = (unsigned long long)op.getInterval() * 1000000; - } + adjustSensor(s, op, u); } return true; } + + /** + * @brief Adjusts a single sensor + * + */ + void adjustSensor(std::shared_ptr s, Operator& op, UnitTemplate& u) { + s->setName(s->getMqtt()); + SensorMetadata* sm = s->getMetadata(); + if(sm) { + if(sm->isOperation) { + s->clearMetadata(); + if(u.getInputs().size() != 1) { + LOG(error) << _operatorName << " " << op.getName() << ": Ambiguous operation field for sensor " << s->getName(); + return; + } + // Replacing the metadata to publish the sensor as an operation of its corresponding input + SensorMetadata smNew; + smNew.publicName = u.getInputs()[0]->getMqtt(); + smNew.addOperation(s->getMqtt()); + s->setMetadata(smNew); + } else { + sm->publicName = s->getMqtt(); + sm->pattern = s->getMqtt(); + sm->isVirtual = false; + if (sm->interval == 0) + sm->interval = (unsigned long long) op.getInterval() * 1000000; + } + } + } /** * @brief Returns true if the input string describes an input block diff --git a/common/include/metadatastore.h b/common/include/metadatastore.h index e5ea80f..37d5bc2 100644 --- a/common/include/metadatastore.h +++ b/common/include/metadatastore.h @@ -47,6 +47,7 @@ class SensorMetadata { public: SensorMetadata() : + isOperation(false), isVirtual(false), integrable(true), monotonic(false), @@ -59,6 +60,7 @@ public: operations("") {} SensorMetadata(const SensorMetadata& other) { + this->isOperation = other.isOperation; this->isVirtual = other.isVirtual; this->integrable = other.integrable; this->monotonic = other.monotonic; @@ -72,6 +74,7 @@ public: } SensorMetadata& operator=(const SensorMetadata& other) { + this->isOperation = other.isOperation; this->isVirtual = other.isVirtual; this->integrable = other.integrable; this->monotonic = other.monotonic; @@ -85,6 +88,19 @@ public: return *this; } + + bool addOperation(const string& opName) { + if (publicName.length()>0 && opName.length()>publicName.length() && !opName.compare(0, publicName.length(), publicName)) { + if(operations.length()==0) + operations = opName.substr(publicName.length()); + else + operations += "," + opName.substr(publicName.length()); + return true; + } + else + return false; + } + /** * @brief Parses a JSON string and stores the content in this object. * @@ -112,6 +128,8 @@ public: this->monotonic = to_bool(val.second.data()); } else if (boost::iequals(val.first, "isVirtual")) { this->isVirtual = to_bool(val.second.data()); + } else if (boost::iequals(val.first, "isOperation")) { + this->isOperation = to_bool(val.second.data()); } else if (boost::iequals(val.first, "integrable")) { this->integrable = to_bool(val.second.data()); } else if (boost::iequals(val.first, "unit")) { @@ -157,6 +175,7 @@ public: } // Public class members + bool isOperation; bool isVirtual; bool integrable; bool monotonic; @@ -200,6 +219,7 @@ protected: std::ostringstream scaleStream; scaleStream << this->scale; config.clear(); + config.push_back(boost::property_tree::ptree::value_type("isOperation", boost::property_tree::ptree(this->isOperation ? "true" : "false"))); config.push_back(boost::property_tree::ptree::value_type("isVirtual", boost::property_tree::ptree(this->isVirtual ? "true" : "false"))); config.push_back(boost::property_tree::ptree::value_type("monotonic", boost::property_tree::ptree(this->monotonic ? "true" : "false"))); config.push_back(boost::property_tree::ptree::value_type("integrable", boost::property_tree::ptree(this->integrable ? "true" : "false"))); diff --git a/dcdbpusher/README.md b/dcdbpusher/README.md index cb9d9cd..e92fcb1 100644 --- a/dcdbpusher/README.md +++ b/dcdbpusher/README.md @@ -748,6 +748,7 @@ Available fields that can be published as metadata are the following: | interval | Sampling interval in milliseconds of the sensor. | | operations | Comma-separated lists of operations available for the sensor, whose values can be retrieved by appending their names to the sensor name. | +An additional _isOperation_ field is available for the output sensors of operators in the Wintermute framework. If these output sensors are generated starting from a single input, this field allows to publish them as _operations_ of the latter, and will be listed in the associated database entry. For this to apply, however, the MQTT topic of the output sensor must be identical to that of the input, plus a suffix that describes the operation. Enabling this option invalidates all other metadata fields. ## Writing own plugins First make sure you read the [plugins](#plugins) section. -- GitLab