ConfiguratorTemplate.h 11 KB
Newer Older
1
/*
2
 * ConfiguratorTemplate.h
3
4
5
6
7
 *
 *  Created on: 13.01.2018
 *      Author: Micha Mueller
 */

8
9
#ifndef SRC_CONFIGURATORTEMPLATE_H_
#define SRC_CONFIGURATORTEMPLATE_H_
10

11
#include "ConfiguratorInterface.h"
12

13
14
#include "SensorBase.h"
#include "SensorGroupTemplate.h"
15

16
17
18
19
20
21
#include <map>

#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/info_parser.hpp>
22

23
24
#define STRCMP(node,str) boost::iequals(node.first,str)

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//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; \
							}


/*
41
42
43
44
45
#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;
46
*/
47

Micha Mueller's avatar
Micha Mueller committed
48
/**
49
 * Non-virtual interface template for the configurators.
Micha Mueller's avatar
Micha Mueller committed
50
 */
51
template <class SBase, class SGroup, class SEntity = void>
52
class ConfiguratorTemplate : public ConfiguratorInterface {
53
	//the template shall only be instantiated for classes which derive from SensorBase/SensorGroup
54
	static_assert(std::is_base_of<SensorBase, SBase>::value, "SBase must derive from SensorBase!");
55
	static_assert(std::is_base_of<SensorGroupTemplate, SGroup>::value, "SGroup must derive from SensorGroupTemplate!");
56

57
protected:
58
59
	typedef std::map<std::string, SGroup> sGroupMap_t;
	typedef std::map<std::string, SEntity> sEntityMap_t;
60

61
public:
62
63
64
65
66
67
68
	ConfiguratorTemplate() :
		_entityName("entity"),
		_groupName("group"),
		_sensorName("sensor"),
		_cfgPath(""),
		_mqttPrefix(""),
		_cacheInterval(900000) {}
69

70
	virtual ~ConfiguratorTemplate() {
71
72
		for (auto g : _sensorGroups) {
			delete g;
73
		}
74
		_templateSensorGroups.clear();
75
		_templateSensorEntitys.clear();
76
	}
77

Micha Mueller's avatar
Micha Mueller committed
78
79
	/**
	 * Read in the given configuration
80
	 *
Micha Mueller's avatar
Micha Mueller committed
81
	 * @param	cfgPath Path to the config-file
82
83
	 *
	 * @return	True on success, false otherwise
Micha Mueller's avatar
Micha Mueller committed
84
	 */
85
	bool readConfig(std::string cfgPath) final {
86
		_cfgPath = cfgPath;
87
88
89
90
91

		boost::property_tree::iptree cfg;
		boost::property_tree::read_info(cfgPath, cfg);

		//read global variables (if present overwrite those from global.conf)
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
		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 Group \"" << tempVal.second.data() << "\"";
					if (!tempVal.second.empty()) {
						SGroup group(tempVal.second.data());
						if (readSensorGroup(group, tempVal.second)) {
							BOOST_FOREACH(boost::property_tree::iptree::value_type &sBaseVal, tempVal.second) {
								if (boost::iequals(sBaseVal.first, _baseName)) {
									SBase* sensor = new SBase(sBaseVal.second.data());
									if (readSensorBase(*sensor, sBaseVal.second)) {
										group.pushBackSensor(sensor);
									} else {
										LOG(warning) << "Template sensor \"" << group.getName() << "::" << sBaseVal.second.data() << "\" has bad values! Ignoring...";
									}
								}
							}
							_templateSensorGroups.insert(std::pair<std::string, SGroup>(group.getName(), group));
						} else {
							LOG(warning) << "Template group \"" << tempVal.second.data() << "\" has bad values! Ignoring...";
						}
119
					}
120
				} //else if (boost::iequals(tempVal.first, _baseName)) {//TODO allow for template sensors? even useful?}
121
122
123
			}
		}

124
125
		//TODO read actual entitys/groups/bases. How to handle defaults?

126
127
		//read template groups
		boost::optional<boost::property_tree::iptree&> tempSens = cfg.get_child_optional("groupTemplates");
128
		if (tempSens) {
129
130
131
132
133
134
135
136
			BOOST_FOREACH(boost::property_tree::iptree::value_type &groupVal, cfg.get_child("groupTemplates")) {
				if (STRCMP(groupVal, "group")) {
					LOG(debug) << "Template Group \"" << 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));
137
						} else {
138
							LOG(warning) << "Template group \"" << groupVal.second.data() << "\" has bad values! Ignoring...";
139
						}
140
141
142
143
144
145
146
					}
				}
			}
		}

		//read in plugin specific stuff (including actual sensors)
		return derivedReadConfig(cfg);
147
148
149
150
	}

	/**
	 * Clear internal storage and read in the configuration again.
151
152
	 *
	 * @return	True on success, false otherwise
153
	 */
154
	bool reReadConfig() final {
Micha Mueller's avatar
Micha Mueller committed
155
156
		//bring everything to a halt
		for(auto g : _sensorGroups) {
157
			g->stop();
Micha Mueller's avatar
Micha Mueller committed
158
159
160
161
162
163
		}

		//wait until everything is halted
		for(auto g : _sensorGroups) {
			g->wait();
		}
164

Micha Mueller's avatar
Micha Mueller committed
165
		//clean up plugin specific stuff
166
167
		derivedReReadConfig();

Micha Mueller's avatar
Micha Mueller committed
168
169
170
171
172
173
		//clean up sensors and groups
		for(auto g : _sensorGroups) {
			delete g;
		}

		_sensorGroups.clear();
174
		_templateSensorGroups.clear();
175

Micha Mueller's avatar
Micha Mueller committed
176
		//back to the very beginning
177
		return readConfig(_cfgPath);
178
	}
179

180
181
182
183
184
185
186
	/**
	 * Sets internal variables with the ones provided by pluginSettings.
	 * This method should be called once after constructing a configurator
	 * to provide him with the global default values.
	 *
	 * @param pluginSettings	Struct with global default settings for the plugins.
	 */
187
	void setGlobalSettings(const pluginSettings_t& pluginSettings) final {
188
189
		_mqttPrefix = pluginSettings.mqttPrefix;
		_cacheInterval = pluginSettings.cacheInterval;
190
191

		derivedSetGlobalSettings(pluginSettings);
192
193
	}

Micha Mueller's avatar
Micha Mueller committed
194
195
196
197
198
	/**
	 * Get all sensor groups
	 *
	 * @return	Vector containing pointers to all sensor groups of this plugin
	 */
199
	std::vector<SensorGroupInterface*>& getSensorGroups() {
Micha Mueller's avatar
Micha Mueller committed
200
201
202
		return _sensorGroups;
	}

203
protected:
204
205
206
207
208
	/**
	 * Non-virtual interface method for class-internal use only.
	 * Reads and sets the common base values of a sensor (currently none),
	 * then calls the corresponding derived function to read plugin specific
	 * values.
209
	 *
210
	 * @param sBase		The sensor base for which to set the values
211
212
213
214
	 * @param config	A boost property (sub-)tree containing the sensor values
	 *
	 * @return	True on success, false otherwise
	 */
215
	bool readSensorBase(SBase& sBase, boost::property_tree::iptree& config) {
216
		return sensorBase(sBase, config);
217
218
219
220
221
222
223
224
225
226
227
228
229
	}

	/**
	 * 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).
	 *
	 * @param sensor	The sensor for which to set the values
	 * @param config	A boost property (sub-)tree containing the sensor values
	 *
	 * @return	True on success, false otherwise
	 */
230
231
232
	bool readSensorGroup(SGroup& sGroup, boost::property_tree::iptree& config) {
		sGroup.setCacheInterval(_cacheInterval);
		//read in values inherited from SensorGroupInterface
233
		BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
234
			//TODO handle default value here?
235
			if (STRCMP(val, "interval")) {
236
				sGroup.setInterval(stoull(val.second.data()));
237
			} else if (STRCMP(val, "minValues")) {
238
239
240
241
242
243
244
245
				sGroup.setMinValues(stoull(val.second.data()));
			} else if (STRCMP(val, "sensor")) {
				SBase* sensor = new SBase(val.second.data());
				if (readSensorBase(*sensor, val.second)) {
					sGroup.pushBackSensor(sensor);
				} else {
					LOG(warning) << "Sensor " << sGroup.getGroupName() << "::" << sensor->getName() << " could not be read! Omitting";
				}
246
247
248
			}
		}

249
250
		LOG(debug) << "  Interval : " << sGroup.getInterval();
		LOG(debug) << "  minValues: " << sGroup.getMinValues();
251

252
253
254
255
256
		return sensorGroup(sGroup, config);
	}

	bool readSensorEntity(SEntity& sEntity, boost::property_tree::iptree& config) {
		return sensorEntity(sEntity, config);
257
258
	}

259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
	bool readGlobal(boost::property_tree::iptree& config) {
		boost::optional<boost::property_tree::iptree&> globalVals = config.get_child_optional("global");
		if (globalVals) {
			BOOST_FOREACH(boost::property_tree::iptree::value_type &global, config.get_child("global")) {
				if (boost::iequals(global.first, "mqttprefix")) {
					_mqttPrefix = global.second.data();
					if (_mqttPrefix[_mqttPrefix.length()-1] != '/') {
						_mqttPrefix.append("/");
					}
					LOG(debug) << "  Using own MQTT-Prefix " << _mqttPrefix;
				} else if (boost::iequals(global.first, "cacheInterval")) {
					_cacheInterval = stoul(global.second.data());
					LOG(debug) << "  Using own caching interval " << _cacheInterval << " [s]";
					_cacheInterval *= 1000;
				}
			}
		}
		return global(config);
	}

279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
	/**
	 * 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
	 * for its plugin.
	 *
	 * @param pluginSettings	The struct with global default plugin settings
	 */
	virtual void derivedSetGlobalSettings(const pluginSettings_t& pluginSettings) = 0;

	/**
	 * Pure virtual interface method, responsible for reading plugin-specific sensor
305
	 * base values.
306
	 *
307
308
309
310
311
	 * @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
	 */
312
	virtual bool sensorBase(SBase& sBase, boost::property_tree::iptree& config) = 0;
313
314
315
316
317
318

	/**
	 * Pure virtual interface method, responsible for reading plugin-specific sensor
	 * group values.
	 *
	 * @param sGroup	The sensor group for which to set the values
319
320
321
322
	 * @param config	A boost property (sub-)tree containing the sensor values
	 *
	 * @return	True on success, false otherwise
	 */
323
324
325
326
	virtual bool sensorGroup(SGroup& sGroup, boost::property_tree::iptree& config) = 0;

	virtual bool sensorEntity(SEntity& sEntity, boost::property_tree::iptree& config) = 0;

327
328
	virtual bool global(boost::property_tree::iptree& config) = 0;

329
330
	std::string		_entityName;
	std::string		_groupName;
331
	std::string		_baseName;
332
333
334
335

	std::string 	_cfgPath;
	std::string		_mqttPrefix;
	unsigned int	_cacheInterval;
336
	std::vector<SensorGroupInterface*> _sensorGroups;
337
338
	sGroupMap_t		_templateSensorGroups;
	sEntityMap_t	_templateSensorEntitys;
339
340
};

341
#endif /* SRC_CONFIGURATORTEMPLATE_H_ */