Commit e3e7d8c7 authored by Micha Mueller's avatar Micha Mueller
Browse files

Outsource code for reading of configuration in own class

Sensors are now an own class as well.
Adapt Makefile accordingly.
It is now possible to define default sysfsSensors in the config.
See sysfspusher.conf for an example.
parent 8b2ea774
......@@ -8,7 +8,7 @@ include $(DCDBCOREPATH)/common.mk
CXXFLAGS = -std=c++0x -O2 -g -Wall -Werror -Wno-unused-local-typedefs -Wno-unknown-warning-option -Wno-deprecated-declarations -I$(DCDBDEPLOYPATH)/include -I$(DCDBBASEPATH)/include
CXXFLAGS = -O2 -g -Wall -Wno-unused-function $(CXX11FLAGS) -I$(DCDBBASEPATH)/dcdb/include -I$(DCDBDEPLOYPATH)/include
LIBS = -L../deps/mosquitto_build/lib -L$(DCDBDEPLOYPATH)/lib/ -lmosquitto
OBJS = sysfspusher.o helper.o
OBJS = sysfspusher.o helper.o SYSFSConfiguration.o SYSFSSensor.o
$(TARGET): $(OBJS)
$(CXX) -o $(TARGET) $(OBJS) $(LIBS)
......
/*
* SYSFSConfiguration.cpp
*
* Created on: 18.11.2017
* Author: micha
*/
//TODO legal disclaimer?
#include "SYSFSConfiguration.h"
#include <iostream>
#include "SYSFSSensor.h"
#include <boost/foreach.hpp>
#include <boost/property_tree/info_parser.hpp>
#include <boost/algorithm/string.hpp>
using namespace std;
SYSFSConfiguration::SYSFSConfiguration(string cfgFile) {
//set default values for global variables
_global.brokerHost = "";
_global.brokerPort = 1883;
_global.mqttPrefix = "";
boost::property_tree::iptree cfg;
boost::property_tree::read_info(cfgFile, cfg);
//read global variables
BOOST_FOREACH(boost::property_tree::iptree::value_type &global, cfg.get_child("global")) {
cout << global.first << " " << global.second.data() << endl;
if(boost::iequals(global.first, "mqttBroker")) {
_global.brokerHost = global.second.data();
size_t pos = _global.brokerHost.find(":");
if (pos != string::npos) {
_global.brokerPort = stoi(_global.brokerHost.substr(pos+1));
_global.brokerHost.erase(pos);
}
} else if(boost::iequals(global.first, "mqttprefix")) {
_global.mqttPrefix = global.second.data();
if (_global.mqttPrefix[_global.mqttPrefix.length()-1] != '/') {
_global.mqttPrefix.append("/");
}
} else {
cout << " Value \"" << global.first << "\" not recognized. Omitting..." << endl;
}
}
//read default sensors
BOOST_FOREACH(boost::property_tree::iptree::value_type &sensor, cfg.get_child("defaultSensors")) {
if (boost::iequals(sensor.first, "sensor")) {
cout << "Default Sensor \"" << sensor.second.data() << "\"" << endl;
if (!sensor.second.empty()) {
SYSFSSensor sysfsSensor(sensor.second.data());
readSensor(sysfsSensor, sensor.second);
_defaultSensors.insert(sensorMap_t::value_type(sysfsSensor.getName(), sysfsSensor));
}
}
}
//read one sensor at a time
BOOST_FOREACH(boost::property_tree::iptree::value_type &sensor, cfg.get_child("sensors")) {
if (boost::iequals(sensor.first, "sensor")) {
cout << "Sensor \"" << sensor.second.data() << "\"" << endl;
if (!sensor.second.empty()) {
SYSFSSensor sysfsSensor(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) {
cout << " Using \"" << defaultS.get().data() << "\" as default." << endl;
sensorMap_t::iterator it = _defaultSensors.find(defaultS.get().data());
if(it != _defaultSensors.end()) {
sysfsSensor = it->second;
sysfsSensor.setName(sensor.second.data());
} else {
cout << "Default sensor \"" << defaultS.get().data() << "\" not found! Using standard values." << endl;
}
}
//read remaining values
readSensor(sysfsSensor, sensor.second);
_sensors.push_back(sysfsSensor);
}
}
}
}
SYSFSConfiguration::~SYSFSConfiguration() {
// TODO Auto-generated destructor stub
}
void SYSFSConfiguration::readSensor(SYSFSSensor& sensor, boost::property_tree::iptree& config) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &s, config) {
if (boost::iequals(s.first, ("path"))) {
sensor.setPath(s.second.data());
} else if (boost::iequals(s.first, "interval")) {
sensor.setInterval(stoi(s.second.data()));
} else if (boost::iequals(s.first, "mqttsuffix")) {
sensor.setMqtt(s.second.data());
} else if (boost::iequals(s.first, "minI")) {
sensor.setConvert(true);
sensor.setMinI(stoull(s.second.data()));
} else if (boost::iequals(s.first, "maxI")) {
sensor.setConvert(true);
sensor.setMaxI(stoull(s.second.data()));
} else if (boost::iequals(s.first, "maxV")) {
sensor.setConvert(true);
sensor.setMaxV(stoull(s.second.data()));
} else if (boost::iequals(s.first, "filter")) {
sensor.setFilter(true);
// Notes on regexes:
// 1. If a \ ("backslash") is needed in the regex (for escaping), always use \\ ("double backslash") as
// the regex is read in as string and strings also escape with backslash
// 2. Whitespaces cannot be used in a regex, as Boost uses them as separators in his property trees.
// Use \\s instead to match a whitespace (\s matches any whitespace character)
// 3. The desired value, which later shall be parsed and stored, should be indicated by a so called group within the regex.
// Groups are created with parentheses. There should only be one group per regex.
// See "http://www.cplusplus.com/reference/regex/ECMAScript/#character_classes" for regex syntax-reference in C++
sensor.setRegex(regex(s.second.data()));
} else if (boost::iequals(s.first, "default")) {
//avoid unnecessary "Value not recognized" message
} else {
cout << " Value \"" << s.first << "\" not recognized. Omitting..." << endl;
}
}
cout << " Path : " << sensor.getPath() << endl;
cout << " MQTT : " << sensor.getMqtt() << endl;
cout << " Interval: " << sensor.getInterval() << endl;
if (sensor.doConvert()) {
cout << " minI : " << sensor.getMinI() << endl;
cout << " maxI : " << sensor.getMaxI() << endl;
cout << " maxV : " << sensor.getMaxV() << endl;
}
if (sensor.hasFilter()) {
//regex cannot be converted back to string
cout << " Using regular expression to filter data" << endl;
}
return;
}
/*
* SYSFSConfiguration.h
*
* Created on: 18.11.2017
* Author: micha
*/
//TODO legal disclaimer?
#ifndef SYSFSCONFIGURATION_H_
#define SYSFSCONFIGURATION_H_
#include <vector>
#include <string>
#include <map>
#include <boost/property_tree/ptree.hpp>
class SYSFSSensor;
class SYSFSConfiguration {
typedef std::vector<SYSFSSensor> sensorVector_t;
typedef std::map<std::string, SYSFSSensor> sensorMap_t;
typedef struct {
int brokerPort;
std::string brokerHost;
std::string mqttPrefix;
} global_t;
public:
/**
* Read the configuration for sysfsPusher.
* @param cfgFile Name of the configuration file.
*/
SYSFSConfiguration(std::string cfgFile);
virtual ~SYSFSConfiguration();
sensorVector_t _sensors;
global_t _global;
private:
/**
* Set the variables of sensor according to the values specified in config.
* @param sensor The sensor to be configured
* @param config A property(sub)tree containing the values
* @return 0 on success, 1 otherwise
*/
void readSensor(SYSFSSensor& sensor, boost::property_tree::iptree& config);
sensorMap_t _defaultSensors;
};
#endif /* SYSFSCONFIGURATION_H_ */
/*
* SYSFSSensor.cpp
*
* Created on: 18.11.2017
* Author: Micha Mueller
*/
//TODO Legal License?
#include "SYSFSSensor.h"
SYSFSSensor::SYSFSSensor(const std::string& name) {
_name = name;
_path = "";
_mqtt = "";
_interval = 1000;
_convert = false;
_minI = 0;
_maxI = 0;
_maxV = 0;
_file = NULL;
_nextRead = 0;
_filter = false;
}
SYSFSSensor::~SYSFSSensor() {
// TODO eventually close _file (if still open)
}
/*
* SYSFSSensor.h
*
* Created on: 18.11.2017
* Author: Micha Mueller
*/
//TODO Legal License?
#ifndef SYSFSSENSOR_H_
#define SYSFSSENSOR_H_
#include <string>
#include <regex>
class SYSFSSensor {
public:
SYSFSSensor(const std::string& name);
virtual ~SYSFSSensor();
const std::string& getName() const {
return _name;
}
void setName(const std::string& name) {
_name = name;
}
const std::string& getPath() const {
return _path;
}
void setPath(const std::string& path) {
_path = path;
}
const std::string& getMqtt() const {
return _mqtt;
}
void setMqtt(const std::string& mqtt) {
_mqtt = mqtt;
}
FILE* getFile() const {
return _file;
}
void setFile(FILE* file) {
_file = file;
}
int getInterval() const {
return _interval;
}
void setInterval(int interval) {
_interval = interval;
}
bool doConvert() const {
return _convert;
}
void setConvert(bool convert) {
_convert = convert;
}
int64_t getMinI() const {
return _minI;
}
void setMinI(int64_t minI) {
_minI = minI;
}
int64_t getMaxI() const {
return _maxI;
}
void setMaxI(int64_t maxI) {
_maxI = maxI;
}
int64_t getMaxV() const {
return _maxV;
}
void setMaxV(int64_t maxV) {
_maxV = maxV;
}
uint64_t getNextRead() const {
return _nextRead;
}
void setNextRead(uint64_t nextRead) {
_nextRead = nextRead;
}
bool hasFilter() const {
return _filter;
}
void setFilter(bool filter) {
_filter = filter;
}
std::regex getRegex() const {
return _regx;
}
void setRegex(std::regex regx) {
_regx = regx;
}
private:
std::string _name;
std::string _path;
std::string _mqtt;
bool _convert;
int64_t _minI;
int64_t _maxI;
int64_t _maxV;
FILE* _file;
int _interval;
uint64_t _nextRead;
bool _filter;
std::regex _regx;
};
#endif /* SYSFSSENSOR_H_ */
......@@ -3,11 +3,22 @@ global {
mqttprefix /00112233445566778899AABB0000
}
defaultSensors {
sensor def1 {
path /home/micha/LRZ/dcdbOwnFork/sysfspusher/temp
interval 1000
mqttsuffix 0000
filter Temperature\\s([[:digit:]]+\\.[[:digit:]]+)°C
}
sensor def2 {
interval 2000
}
}
sensors {
sensor temp0 {
path /sys/devices/virtual/thermal/thermal_zone0/temp
interval 1000
mqttsuffix 0000
default def1
}
sensor temp1 {
......@@ -17,14 +28,15 @@ sensors {
}
sensor freq0 {
path /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
path /home/micha/LRZ/dcdbOwnFork/sysfspusher/freq
interval 1000
mqttsuffix 0010
filter Frequency=([[:digit:]]+)
}
sensor freq1 {
path /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq
interval 1000
default def2
mqttsuffix 0011
}
}
......
......@@ -38,32 +38,17 @@
#include <string>
#include <regex>
#include "helper.h"
#include "SYSFSSensor.h"
#include "SYSFSConfiguration.h"
#include <boost/foreach.hpp>
#include <boost/property_tree/ptree.hpp>
//To be removed:
//#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/info_parser.hpp>
#include <boost/algorithm/string.hpp>
using namespace std;
typedef struct {
string name;
string path;
string mqtt;
bool convert;
int64_t minI;
int64_t maxI;
int64_t maxV;
FILE* file;
int interval;
uint64_t nextRead;
bool filter;
regex regx;
} sensor_t;
vector<sensor_t> sensorList;
vector<SYSFSSensor> sensorList;
int brokerPort;
string brokerHost;
string mqttprefix;
......@@ -125,224 +110,15 @@ int readConfiguration(int argc, char **argv) {
}
}
boost::property_tree::iptree cfg;
boost::property_tree::read_info(argv[argc-1], cfg);
//read global variables
BOOST_FOREACH(boost::property_tree::iptree::value_type &global, cfg.get_child("global")) {
std::cout << global.first << " " << global.second.data() << std::endl;
if(boost::iequals(global.first, "mqttBroker")) {
brokerHost = global.second.data();
size_t pos = brokerHost.find(":");
if (pos != string::npos) {
brokerPort = stoi(brokerHost.substr(pos+1));
brokerHost.erase(pos);
} else {
brokerPort = 1883;
}
} else if(boost::iequals(global.first, "mqttprefix")) {
mqttprefix = global.second.data();
if (mqttprefix[mqttprefix.length()-1] != '/') {
mqttprefix.append("/");
}
}
}
//config file values will overwrite command-line options...
SYSFSConfiguration cfg(argv[argc-1]);
//read one sensor at a time
BOOST_FOREACH(boost::property_tree::iptree::value_type &sensor, cfg.get_child("sensors")) {
if (boost::iequals(sensor.first, "sensor")) {
std::cout << "Sensor \"" << sensor.second.data() << "\"" << std::endl;
if (!sensor.second.empty()) {
sensor_t sensorConfig;
sensorConfig.name = sensor.second.data();
sensorConfig.path = "";
sensorConfig.interval = 1000;
sensorConfig.mqtt = "";
sensorConfig.convert = false;
sensorConfig.filter = false;
//read in every value for the sensor
BOOST_FOREACH(boost::property_tree::iptree::value_type &s, sensor.second) {
if (boost::iequals(s.first, ("path"))) {
sensorConfig.path = s.second.data();
} else if (boost::iequals(s.first, "interval")) {
sensorConfig.interval = stoi(s.second.data());
} else if (boost::iequals(s.first, "mqttsuffix")) {
sensorConfig.mqtt = s.second.data();
} else if (boost::iequals(s.first, "minI")) {
sensorConfig.convert = true;
sensorConfig.minI = stoull(s.second.data());
} else if (boost::iequals(s.first, "maxI")) {
sensorConfig.convert = true;
sensorConfig.maxI = stoull(s.second.data());
} else if (boost::iequals(s.first, "maxV")) {
sensorConfig.convert = true;
sensorConfig.maxV = stoull(s.second.data());
} else if (boost::iequals(s.first, "filter")) {
sensorConfig.filter = true;
// Notes on regexes:
// 1. If a \ ("backslash") is needed in the regex (for escaping), always use \\ ("double backslash") as
// the regex is read in as string and strings also escape with backslash
// 2. Whitespaces cannot be used in a regex, as Boost uses them as separators in his property trees.
// Use \\s instead to match a whitespace (\s matches any whitespace character)
// 3. The desired value, which later shall be parsed and stored, should be indicated by a so called group within the regex.
// Groups are created with parentheses. There should only be one group per regex.
// See "http://www.cplusplus.com/reference/regex/ECMAScript/#character_classes" for regex syntax-reference in C++
sensorConfig.regx = regex(s.second.data());
} else {
cout << " Value \"" << s.first << "\" not recognized. Omitting..." << endl;
}
}
cout << " Path : " << sensorConfig.path << endl;
cout << " MQTT : " << sensorConfig.mqtt << endl;
cout << " Interval: " << sensorConfig.interval << endl;
if (sensorConfig.convert) {
cout << " minI : " << sensorConfig.minI << endl;
cout << " maxI : " << sensorConfig.maxI << endl;
cout << " maxV : " << sensorConfig.maxV << endl;
}
if (sensorConfig.filter) {
//regex cannot be converted back to string
cout << " Using regular expression to filter data" << endl;
}
sensorList.push_back(sensorConfig);
}
}
}
//To be removed:
/*
using namespace boost::property_tree;
ptree pt;
ini_parser::read_ini(argv[argc-1], pt);
brokerHost = cfg._global.brokerHost;
brokerPort = cfg._global.brokerPort;
mqttprefix = cfg._global.mqttPrefix;
if (brokerHost.length() == 0) {
brokerHost = pt.get<string>("broker");
}
size_t pos = brokerHost.find(":");
if (pos != string::npos) {
brokerPort = atoi(brokerHost.substr(pos+1).c_str());
brokerHost.erase(pos);
} else {
brokerPort = 1883;
}
sensorList = cfg._sensors;
if (mqttprefix.length() == 0) {
mqttprefix = pt.get<string>("mqttprefix");
}
if (mqttprefix[mqttprefix.length()-1] != '/') {
mqttprefix.append("/");
}
cout << "MQTT Broker: " << brokerHost << ":" << brokerPort << endl;
cout << "MQTT Prefix: " << mqttprefix << endl;
BOOST_FOREACH(ptree::value_type &v, pt) {
if (!v.second.empty()) {
sensor_t sensorConfig;
sensorConfig.name = v.first.data();
sensorConfig.path = "";
sensorConfig.interval = 1000;
sensorConfig.mqtt = "";
sensorConfig.convert = false;
BOOST_FOREACH(ptree::value_type &v2, pt.get_child(v.first.data())) {
const char* dataName = v2.first.data();
string sn(v.first.data());
if (strcasecmp(dataName, "path") == 0) {
if (verbose) {
cout << "getting " << sn << ".path..." << endl;
}
sensorConfig.path = pt.get<string>(sn + ".path");
} else if (strcasecmp(dataName, "interval") == 0) {
sensorConfig.interval = pt.get<int>(sn + ".interval");
} else if (strcasecmp(dataName, "mqtt") == 0) {
sensorConfig.mqtt = pt.get<string>(sn + ".mqtt");
} else if (strcasecmp(dataName, "minI") == 0) {
sensorConfig.convert = true;
sensorConfig.minI = pt.get<uint64_t>(sn + ".minI");
} else if (strcasecmp(dataName, "maxI") == 0) {
sensorConfig.convert = true;
sensorConfig.maxI = pt.get<uint64_t>(sn + ".maxI");
} else if (strcasecmp(dataName, "maxV") == 0) {
sensorConfig.convert = true;
sensorConfig.maxV = pt.get<uint64_t>(sn + ".maxV");
}
}
cout << "Sensor \"" << sensorConfig.name << "\"" << endl;
cout << " Path : " << sensorConfig.path << endl;
cout << " MQTT : " << sensorConfig.mqtt << endl;
cout << " Interval: " << sensorConfig.interval << endl;
if (sensorConfig.convert) {
cout << " minI : " << sensorConfig.minI << endl;
cout << " maxI : " << sensorConfig.maxI << endl;
cout << " maxV : " << sensorConfig.maxV << endl;
}
sensorList.push_back(sensorConfig);
}
}*/
#if 0
for (int i = 0; i < config.getNumSections(); i++) {
const char* sectionName = config.getSectionNameAt(i);
if (strlen(sectionName) == 0) {
config.setSection(sectionName);
for (int j = 0; j < config.getNumDataMembers(); j++) {
const char* dataName = config.getDataNameAt(j);
if (strcasecmp(dataName, "broker") == 0) {
broker = config.getStringValue(dataName);
cout << "Broker: " << broker << endl;
}
else if (strcasecmp(dataName, "mqttprefix") == 0) {
mqttprefix = config.getStringValue(dataName);
cout << "MQTT prefix: " << mqttprefix << endl;
}