Commit 5ee328cf authored by Micha Mueller's avatar Micha Mueller
Browse files

Finish configurator overhaul. TODO: Make it compile + run; Adapt all plugins

parent 038f1ab7
global {
cacheInterval 60
mqttprefix /AABBAABBAABBAACCDDCCDDCC
}
template_group temp1 {
interval 1000
mqttprefix 01
minValues 1
gAtt 0
sensor s1 {
mqttsuffix 01
sAtt 0
}
sensor s2 {
mqttsuffix 02
sAtt 1
}
}
template_entity entity1 {
host localhost
port 1234
group g1 {
default temp1
}
}
group g1 {
default temp1
gAtt 2
mqttprefix 02
}
group g2 {
interval 1000
mqttprefix 10
minValues 1
gAtt 1
sensor se1 {
mqttsuffix 01
sAtt a
}
sensor se2 {
mqttsuffix 02
sAtt b
}
}
entity e1 {
default entity1
group g3 {
default temp1
gAtt 3
mqttpart 02
sensor se3 {
mqttsuffix 3
sAtt c
}
}
}
......@@ -20,35 +20,16 @@
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/info_parser.hpp>
#define STRCMP(node,str) boost::iequals(node.first,str)
//#define STRCMP(node,str) boost::iequals(node.first,str) //DEPRECATED
#define CFG_TREE boost::property_tree::iptree&
//TODO how to set mqttsuffix? (_mqttprefix + (mqttpart) + suffix)
#define LOOP_HEADER BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) { \
if (false) {}
#define S_BASE_ATTRIBUTES bool sensorBase(S_BASE& obj, boost::property_tree::iptree& config) override { \
LOOP_HEADER
#define S_GROUP_ATTRIBUTES bool sensorGroup(S_GROUP& obj, boost::property_tree::iptree& config) override { \
LOOP_HEADER
#define S_ENTITY_ATTRIBUTES bool sensorEntity(S_ENTITY& obj, boost::property_tree::iptree& config) override { \
LOOP_HEADER
#define ADD(name,setter) else if (boost::iequals(val.first, name)) { obj.setter(val.second.data()); }
#define END_ATTRIBUTES } return true; \
}
/*
#define CONFIG boost::property_tree::iptree& config
#define ATTRIBUTES BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) { \
if (false) {}
#define ADD(name,setter) else if (boost::iequals(val.first, name)) { sBase.setter(val.second.data()); }
#define END } return true;
*/
#define ADD BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config)
#define ATTRIBUTE(name,setter) if (boost::iequals(val.first, name)) { s.setter(val.second.data()); }
/**
* Non-virtual interface template for the configurators.
*/
template <class SBase, class SGroup, class SEntity = void>
template <class SBase, class SGroup, class SEntity = nullptr_t>
class ConfiguratorTemplate : public ConfiguratorInterface {
//the template shall only be instantiated for classes which derive from SensorBase/SensorGroup
static_assert(std::is_base_of<SensorBase, SBase>::value, "SBase must derive from SensorBase!");
......@@ -60,9 +41,9 @@ protected:
public:
ConfiguratorTemplate() :
_entityName("entity"),
_groupName("group"),
_baseName("sensor"),
_entityName("INVALID"),
_groupName("INVALID"),
_baseName("INVALID"),
_cfgPath(""),
_mqttPrefix(""),
_cacheInterval(900000) {}
......@@ -73,12 +54,17 @@ public:
for (auto g : _sensorGroups) {
delete g;
}
for (auto e : _sensorEntitys) {
delete e;
}
for (auto tg : _templateSensorGroups) {
delete tg;
delete tg.second;
}
for (auto te : _templateSensorEntitys) {
delete te;
delete te.second;
}
_sensorGroups.clear();
_sensorEntitys.clear();
_templateSensorGroups.clear();
_templateSensorEntitys.clear();
}
......@@ -101,52 +87,62 @@ public:
//read global variables (if present overwrite those from global.conf)
readGlobal(cfg);
//read template stuff
boost::optional<boost::property_tree::iptree&> templates = cfg.get_child_optional("templates");
if (templates) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &tempVal, cfg.get_child("templates")) {
if (boost::iequals(tempVal.first, _entityName)) {
//TODO
} else if (boost::iequals(tempVal.first, _groupName)) {
LOG(debug) << "Template " << _groupName << " \"" << tempVal.second.data() << "\"";
if (!tempVal.second.empty()) {
SGroup* group = new SGroup(tempVal.second.data());
if (readSensorGroup(*group, tempVal.second)) {
auto ret = _templateSensorGroups.insert(std::pair<std::string, SGroup*>(group->getName(), group));
if(!ret.second) {
LOG(warning) << "Template " << _groupName << " " << group->getName() << " already exists! Omitting...";
}
} else {
LOG(warning) << "Template " << _groupName << " \"" << tempVal.second.data() << "\" has bad values! Ignoring...";
//read groups and templates for groups. If present also entity/-template stuff
BOOST_FOREACH(boost::property_tree::iptree::value_type &val, cfg) {
//TODO allow for template sensors?
//template entity
if (boost::iequals(val.first, "template_" + _entityName)) {
LOG(debug) << "Template " << _entityName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
SEntity* entity = new SEntity(val.second.data());
if (readSensorEntity(*entity, val.second)) {
auto ret = _templateSensorEntitys.insert(std::pair<std::string, SEntity*>(entity->getName(), entity));
if(!ret.second) {
LOG(warning) << "Template " << _entityName << " " << entity->getName() << " already exists! Omitting...";
}
} else {
LOG(warning) << "Template " << _entityName << " \"" << val.second.data() << "\" has bad values! Ignoring...";
}
}
//template group
} else if (boost::iequals(val.first, "template_" + _groupName)) {
LOG(debug) << "Template " << _groupName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
SGroup* group = new SGroup(val.second.data());
if (readSensorGroup(*group, val.second)) {
auto ret = _templateSensorGroups.insert(std::pair<std::string, SGroup*>(group->getName(), group));
if(!ret.second) {
LOG(warning) << "Template " << _groupName << " " << group->getName() << " already exists! Omitting...";
}
} else {
LOG(warning) << "Template " << _groupName << " \"" << val.second.data() << "\" has bad values! Ignoring...";
}
}
//entity
} else if (boost::iequals(val.first, _entityName)) {
LOG(debug) << _entityName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
SEntity* entity = new SEntity(val.second.data());
if (readSensorEntity(*entity, val.second)) {
_sensorEntitys.push_back(entity);
} else {
LOG(warning) << _entityName << " \"" << val.second.data() << "\" has bad values! Ignoring...";
}
} //else if (boost::iequals(tempVal.first, _baseName)) {//TODO allow for template sensors? even useful?}
}
//group
} else if (boost::iequals(val.first, _groupName)) {
LOG(debug) << _groupName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
SGroup* group = new SGroup(val.second.data());
if (readSensorGroup(*group, val.second)) {
_sensorGroups.push_back(group);
} else {
LOG(warning) << _groupName << " \"" << val.second.data() << "\" has bad values! Ignoring...";
}
}
}
}
//TODO read actual entitys/groups/bases. How to handle defaults?
// //read template groups
// boost::optional<boost::property_tree::iptree&> tempSens = cfg.get_child_optional("groupTemplates");
// if (tempSens) {
// BOOST_FOREACH(boost::property_tree::iptree::value_type &groupVal, cfg.get_child("groupTemplates")) {
// if (STRCMP(groupVal, "group")) {
// LOG(debug) << "Template " << _groupName << " \"" << groupVal.second.data() << "\"";
// if (!groupVal.second.empty()) {
// //TODO
// SGroup group(groupVal.second.data());
// if(readSensorGroup(group, groupVal.second)) {
// _templateSensorGroups.insert(std::pair<std::string, SGroup>(group.getName(), group));
// } else {
// LOG(warning) << "Template " << _groupName << " \"" << groupVal.second.data() << "\" has bad values! Ignoring...";
// }
// }
// }
// }
// }
//read in plugin specific stuff (including actual sensors)
return derivedReadConfig(cfg);
return true;
}
/**
......@@ -165,20 +161,21 @@ public:
g->wait();
}
//clean up plugin specific stuff
derivedReReadConfig();
//clean up sensors/groups and templates
//clean up sensors/groups/entitys and templates
for(auto g : _sensorGroups) {
delete g;
}
for(auto e : _sensorEntitys) {
delete e;
}
for (auto tg : _templateSensorGroups) {
delete tg;
delete tg.second;
}
for (auto te : _templateSensorEntitys) {
delete te;
delete te.second;
}
_sensorGroups.clear();
_sensorEntitys.clear();
_templateSensorGroups.clear();
_templateSensorEntitys.clear();
......@@ -212,7 +209,7 @@ public:
protected:
/**
* Non-virtual interface method for class-internal use only.
* Reads and sets the common base values of a sensor (currently none),
* Reads and sets the common base values of a sensor base (currently none),
* then calls the corresponding derived function to read plugin specific
* values.
*
......@@ -222,50 +219,96 @@ protected:
* @return True on success, false otherwise
*/
bool readSensorBase(SBase& sBase, boost::property_tree::iptree& config) {
return sensorBase(sBase, config);
//TODO set full mqtt-topic if reading config finished!
//TODO default templates useful?
BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
if (boost::iequals(val.first, "mqttsuffix")) {
sBase.setMqtt(val.second.data());
}
}
sensorBase(sBase, config);
return true;
}
/**
* Non-virtual interface method for class-internal use only.
* Reads and sets the common base values of a SensorInterface, then calls
* the corresponding derived function to read in plugin specific values
* (currently none).
* Reads and sets the common base values of a sensor group, then calls
* the corresponding derived function to read in plugin specific values.
*
* @param sensor The sensor for which to set the values
* @param sGroup The sensor group for which to set the values
* @param config A boost property (sub-)tree containing the sensor values
*
* @return True on success, false otherwise
*/
bool readSensorGroup(SGroup& sGroup, boost::property_tree::iptree& config) {
sGroup.setCacheInterval(_cacheInterval);
//first check if default group is given
boost::optional<boost::property_tree::iptree&> def = config.get_child_optional("default");
if(def) {
//we copy all values from default (including copy constructing its sensors)
//if own sensors are specified they are appended
LOG(debug) << " Using \"" << def.get().data() << "\" as default.";
auto it = _templateSensorGroups.find(def.get().data());
if(it != _templateSensorGroups.end()) {
sGroup = it->second;
sGroup->setName(config.data());
} else {
LOG(warning) << "Template " << _groupName << "\"" << def.get().data() << "\" not found! Using standard values.";
}
}
//read in values inherited from SensorGroupInterface
BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
//TODO handle default value here?
if (STRCMP(val, "interval")) {
if (boost::iequals(val.first, "interval")) {
sGroup.setInterval(stoull(val.second.data()));
} else if (STRCMP(val, "minValues")) {
} else if (boost::iequals(val.first, "minValues")) {
sGroup.setMinValues(stoull(val.second.data()));
} else if (STRCMP(val, "sensor")) {
} else if (boost::iequals(val.first, "mqttPart")) {
sGroup.setMqttPart(val.second.data());
} else if (boost::iequals(val.first, "sensor")) {
SBase* sensor = new SBase(val.second.data());
if (readSensorBase(*sensor, val.second)) {
auto ret = sGroup.pushBackSensor(sensor);
if(!ret.second) {
LOG(warning) << _baseName << " " << sensor->getName() << " already exists! Omitting...";
}
sGroup.pushBackSensor(sensor);
} else {
LOG(warning) << _baseName << " " << sGroup.getGroupName() << "::" << sensor->getName() << " could not be read! Omitting";
}
}
}
LOG(debug) << " Interval : " << sGroup.getInterval();
LOG(debug) << " minValues: " << sGroup.getMinValues();
//TODO keep debug logging for config?
// LOG(debug) << " Interval : " << sGroup.getInterval();
// LOG(debug) << " minValues: " << sGroup.getMinValues();
return sensorGroup(sGroup, config);
sensorGroup(sGroup, config);
return true;
}
/**
* Non-virtual interface method for class-internal use only.
* Reads and sets the common base values of a sensor entity, then calls
* the corresponding derived function to read in plugin specific values.
*
* @param sEntity The aggregating entity for which to set the values
* @param config A boost property (sub-)tree containing the sensor values
*
* @return True on success, false otherwise
*/
bool readSensorEntity(SEntity& sEntity, boost::property_tree::iptree& config) {
return sensorEntity(sEntity, config);
//first check if default entity is given
boost::optional<boost::property_tree::iptree&> def = config.get_child_optional("default");
if(def) {
//we copy all values from default
LOG(debug) << " Using \"" << def.get().data() << "\" as default.";
auto it = _templateSensorEntitys.find(def.get().data());
if(it != _templateSensorEntitys.end()) {
sEntity = it->second;
sEntity->setName(config.data());
} else {
LOG(warning) << "Template " << _entityName << "\"" << def.get().data() << "\" not found! Using standard values.";
}
}
sensorEntity(sEntity, config);
return true;
}
bool readGlobal(boost::property_tree::iptree& config) {
......@@ -285,32 +328,19 @@ protected:
}
}
}
return global(config);
global(config);
return true;
}
/**
* Pure virtual interface method, responsible for reading the plugin-specific
* configuration part.
*
* @param cfg The (root) boost property tree from the plugins configuration file
*
* @return True on success, false otherwise
*/
virtual bool derivedReadConfig(boost::property_tree::iptree& cfg) = 0;
/**
* Pure virtual interface method, responsible for the plugin specific part if
* re-reading the config.
*/
virtual void derivedReReadConfig() = 0;
/**
* Pure virtual interface method, responsible for setting global values specifically
* Virtual interface method, responsible for setting global values specifically
* for its plugin.
*
* @param pluginSettings The struct with global default plugin settings
*/
virtual void derivedSetGlobalSettings(const pluginSettings_t& pluginSettings) = 0;
virtual void derivedSetGlobalSettings(const pluginSettings_t& pluginSettings) {
//Overwrite if necessary
}
/**
* Pure virtual interface method, responsible for reading plugin-specific sensor
......@@ -318,25 +348,36 @@ protected:
*
* @param sBase The sensor base for which to set the values
* @param config A boost property (sub-)tree containing the sensor values
*
* @return True on success, false otherwise
*/
virtual bool sensorBase(SBase& sBase, boost::property_tree::iptree& config) = 0;
virtual void sensorBase(SBase& s, boost::property_tree::iptree& config) = 0;
/**
* Pure virtual interface method, responsible for reading plugin-specific sensor
* group values.
*
* @param sGroup The sensor group for which to set the values
* @param config A boost property (sub-)tree containing the sensor values
*
* @return True on success, false otherwise
* @param config A boost property (sub-)tree containing the group values
*/
virtual bool sensorGroup(SGroup& sGroup, boost::property_tree::iptree& config) = 0;
virtual void sensorGroup(SGroup& s, boost::property_tree::iptree& config) = 0;
virtual bool sensorEntity(SEntity& sEntity, boost::property_tree::iptree& config) = 0;
/**
* Virtual interface method, responsible for reading plugin-specific sensor
* entity values.
*
* @param sEntity The sensor entity for which to set the values
* @param config A boost property (sub-)tree containing the entity values
*/
virtual void sensorEntity(SEntity& s, boost::property_tree::iptree& config) {
//Overwrite if necessary
LOG(warning) << "Method sensorEntity called, but was not overwritten! Either you have unwanted entitys in your config file or forgot to overwrite this method";
}
virtual bool global(boost::property_tree::iptree& config) = 0;
/**
* Virtual interface method, responsible for reading plugin-specific global values.
*
* @param config A boost property (sub-)tree containing the global values
*/
virtual void global(boost::property_tree::iptree& config) {}
std::string _entityName;
std::string _groupName;
......@@ -346,6 +387,7 @@ protected:
std::string _mqttPrefix;
unsigned int _cacheInterval;
std::vector<SensorGroupInterface*> _sensorGroups;
std::vector<SEntity*> _sensorEntitys;
sGroupMap_t _templateSensorGroups;
sEntityMap_t _templateSensorEntitys;
};
......
......@@ -19,6 +19,7 @@ class SensorGroupInterface {
public:
SensorGroupInterface(const std::string& groupName) :
_groupName(groupName),
_mqttPart(""),
_keepRunning(0),
_minValues(1),
_interval(1000),
......@@ -30,6 +31,7 @@ public:
SensorGroupInterface(const SensorGroupInterface& other) :
_groupName(other._groupName),
_mqttPart(other._mqttPart),
_keepRunning(other._keepRunning),
_minValues(other._minValues),
_interval(other._interval),
......@@ -44,6 +46,7 @@ public:
SensorGroupInterface& operator=(const SensorGroupInterface& other) {
_groupName = other._groupName;
_mqttPart = other._mqttPart;
_keepRunning = other._keepRunning;
_minValues = other._minValues;
_interval = other._interval;
......@@ -57,11 +60,13 @@ public:
}
const std::string& getGroupName() const { return _groupName; }
const std::string& getMqttPart() const { return _mqttPart; }
unsigned getMinValues() const { return _minValues; }
unsigned getInterval() const { return _interval; }
unsigned getCacheSize() const { return _cacheSize; }
void setGroupName(const std::string& groupName) { _groupName = groupName; }
void setMqttPart(const std::string& mqttPart) { _mqttPart = mqttPart; }
void setMinValues(unsigned minValues) { _minValues = minValues; }
void setInterval(unsigned interval) { _interval = interval; }
void setCacheInterval(unsigned cacheInterval) { _cacheInterval = cacheInterval; }
......@@ -93,6 +98,7 @@ protected:
virtual void readAsync() = 0;
std::string _groupName;
std::string _mqttPart;
int _keepRunning;
unsigned int _minValues;
unsigned int _interval;
......
......@@ -7,38 +7,13 @@
#include "SysfsConfigurator.h"
#include <iostream>
using namespace std;
bool SysfsConfigurator::derivedReadConfig(boost::property_tree::iptree& cfg) {
//read one sensor at a time
BOOST_FOREACH(boost::property_tree::iptree::value_type &sensor, cfg.get_child("sensors")) {
if (STRCMP(sensor, "sensor")) {
LOG(debug) << "Sensor \"" << sensor.second.data() << "\"";
if (!sensor.second.empty()) {
SysfsSingleSensor* sysfsSensor = new SysfsSingleSensor(sensor.second.data());
//first check if default sensor is given
boost::optional<boost::property_tree::iptree&> defaultS = sensor.second.get_child_optional("default");
if(defaultS) {
LOG(debug) << " Using \"" << defaultS.get().data() << "\" as default.";
sensorMap_t::iterator it = _templateSensors.find(defaultS.get().data());
if(it != _templateSensors.end()) {
*sysfsSensor = it->second;
sysfsSensor->setName(sensor.second.data());
} else {
LOG(warning) << "Template sensor \"" << defaultS.get().data() << "\" not found! Using standard values.";
}
}
//read remaining values
if(readSensorBase(*sysfsSensor, sensor.second)) {
_sensors.push_back(sysfsSensor);
} else {
LOG(warning) << " Sensor \"" << sensor.second.data() << "\" has bad values! Ignoring...";
}
}
}
void SysfsConfigurator::sensorBase(SysfsSensorBase& s, CFG_TREE config) {
ADD {
ATTRIBUTE("path", setPath)
ATTRIBUTE("filter", setFilter)
}
return true;
}
void SysfsConfigurator::sensorGroup(SysfsSensorGroup& s, CFG_TREE config) {
//no group attributes currently
}
......@@ -12,15 +12,10 @@
#include "SysfsSensorGroup.h"
class SysfsConfigurator : public ConfiguratorTemplate<SysfsSensorBase, SysfsSensorGroup, void> {
#define S_BASE SysfsSensorBase
#define S_GROUP SysfsSensorGroup
#define S_ENTITY void
class SysfsConfigurator : public ConfiguratorTemplate<SysfsSensorBase, SysfsSensorGroup> {
public:
SysfsConfigurator() {
_entityName = "host";
_groupName = "group";
_baseName = "sensor";
}
......@@ -29,23 +24,8 @@ public:
protected:
/* Overwritten from ConfiguratorTemplate */
bool derivedReadConfig(boost::property_tree::iptree& cfg) override;
void derivedReReadConfig() override { /* nothing to overwrite */ }
void derivedSetGlobalSettings(const pluginSettings_t& pluginSettings) override { /* nothing to overwrite */ }
bool global(boost::property_tree::iptree& config) override { /* No plugin specific global settings */ return true; }
S_BASE_ATTRIBUTES
ADD("mqttsuffix", setMqtt)
ADD("path", setPath)
ADD("filter", setFilter)
END_ATTRIBUTES