BACnetConfigurator.cpp 6.62 KB
Newer Older
1
2
3
4
5
6
7
8
9
/*
 * BACnetConfigurator.cpp
 *
 *  Created on: 14.04.2018
 *      Author: Micha Mueller
 */

#include "BACnetConfigurator.h"

10
11
12
13
14
15
#include <boost/property_tree/info_parser.hpp>
#include <boost/foreach.hpp>
#include <boost/optional.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>

16
BACnetConfigurator::BACnetConfigurator() {
17
	_bacClient = NULL;
18
19
20
21
22
23
}

BACnetConfigurator::~BACnetConfigurator() {
	for(auto s : _sensors) {
		delete s;
	}
24
	delete _bacClient;
25
26
27
}

std::vector<Sensor*>& BACnetConfigurator::readConfig(std::string cfgPath) {
28
29
30
31
32
33
	boost::property_tree::iptree cfg;
	boost::property_tree::read_info(cfgPath, cfg);

	_bacClient = new BACnetClient();
	std::string interface, mqttPartDevice, mqttPartObject;
	unsigned port = 47808, apdu_timeout = 200, apdu_retries = 0;
34
35
	unsigned deviceInstance = 0, objInstance = 0;
	BACNET_OBJECT_TYPE objType = OBJECT_DEVICE; /* = 8 */
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

	//read global variables (if present overwrite those from global.conf)
	BOOST_FOREACH(boost::property_tree::iptree::value_type &global, cfg.get_child("global")) {
		if (boost::iequals(global.first, "interface")) {
			interface = global.second.data();
			LOG(debug) << "  Interface " << interface;
		} else if (boost::iequals(global.first, "port")) {
			port = stoul(global.second.data());
			LOG(debug) << "  Port " << port;
		} else if (boost::iequals(global.first, "apdu_timeout")) {
			apdu_timeout = stoul(global.second.data());
			LOG(debug) << "  apdu_timeout " << apdu_timeout;
		} else if (boost::iequals(global.first, "apdu_retries")) {
			apdu_retries = stoul(global.second.data());
			LOG(debug) << "  apdu_retries " << apdu_retries;
		} else if (boost::iequals(global.first, "mqttprefix")) {
			_mqttPrefix = global.second.data();
			LOG(debug) << "  Using own MQTT-Prefix " << _mqttPrefix;
		} else {
			LOG(error) << "  Value \"" << global.first << "\" not recognized. Omitting...";
		}
	}

	try {
		_bacClient->init(interface, port, apdu_timeout, apdu_retries);
	} catch (const std::exception& e) {
		LOG(error) << "Could not initialize BACnetClient!";
63
		return _sensors;
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
	}

	//read template sensors
	BOOST_FOREACH(boost::property_tree::iptree::value_type &sensor, cfg.get_child("templates")) {
		if (boost::iequals(sensor.first, "property")) {
			LOG(debug) << "Template Sensor \"" << sensor.second.data() << "\"";
			if (!sensor.second.empty()) {
				BACnetSensor bacnetSensor(sensor.second.data());
				if(readSensor(bacnetSensor, sensor.second)) {
					_templateSensors.insert(sensorMap_t::value_type(bacnetSensor.getName(), bacnetSensor));
				} else {
					LOG(warning) << "Template sensor \"" << sensor.second.data() << "\" has bad values! Ignoring...";
				}
			}
		}
	}

	BOOST_FOREACH(boost::property_tree::iptree::value_type &device, cfg.get_child("devices")) {
		if (boost::iequals(device.first, ("device"))) {
			LOG(debug) << "Device " << device.second.data();
			if (!device.second.empty()) {
				BOOST_FOREACH(boost::property_tree::iptree::value_type &d, device.second) {
					if (boost::iequals(d.first, "instance")) {
						deviceInstance = stoul(d.second.data());
					} else if (boost::iequals(d.first, "mqttPart")) {
						mqttPartDevice = d.second.data();
					} else if (boost::iequals(d.first, "object")) {
						LOG(debug) << "Object \"" << d.second.data() << "\"";
						if (!d.second.empty()) {
							BOOST_FOREACH(boost::property_tree::iptree::value_type &object, d.second) {
								if (boost::iequals(object.first, "type")) {
									objType = static_cast<BACNET_OBJECT_TYPE>(stoul(object.second.data()));
								} else if (boost::iequals(object.first, "instance")) {
									objInstance = stoul(object.second.data());
								} else if (boost::iequals(object.first, "mqttPart")) {
									mqttPartObject = object.second.data();
								} else if (boost::iequals(object.first, "property")) {
									LOG(debug) << "Property \"" << object.second.data() << "\"";
									if (!object.second.empty()) {
103
104
105
106
107
108
109
110
111
112
										BACnetSensor * bacSensor = new BACnetSensor(object.second.data());

										//first check if default sensor is given
										boost::optional<boost::property_tree::iptree&> defaultC = object.second.get_child_optional("default");
										if(defaultC) {
											LOG(debug) << "  Using \"" << defaultC.get().data() << "\" as default.";
											sensorMap_t::iterator it = _templateSensors.find(defaultC.get().data());
											if(it != _templateSensors.end()) {
												*bacSensor = it->second;
												bacSensor->setName(object.second.data());
113
											} else {
114
												LOG(warning) << "  Template sensor \"" << defaultC.get().data() << "\" not found! Using standard values.";
115
											}
116
										}
117

118
119
120
121
122
123
124
125
126
127
128
129
										//set object and device related data as well as BACnetClient instance
										//assume property aka sensors are read at last
										bacSensor->setDeviceInstance(deviceInstance);
										bacSensor->setObjectInstance(objInstance);
										bacSensor->setObjectType(objType);
										bacSensor->setMqtt(_mqttPrefix + mqttPartDevice + mqttPartObject);
										bacSensor->setBACnetClient(_bacClient);
										//read remaining values
										if(readSensor(*bacSensor, object.second)) {
											_sensors.push_back(bacSensor);
										} else {
											LOG(warning) << "  Sensor \"" << object.second.data() << "\" has bad values! Ignoring..." << std::endl;
130
131
132
133
134
135
136
137
138
139
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
140
141
142
	return _sensors;
}

143
bool BACnetConfigurator::readSensor(BACnetSensor& sensor, boost::property_tree::iptree& config) {
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
	BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
		if (boost::iequals(val.first, "interval")) {
			sensor.setInterval(stoull(val.second.data()));
		} else if (boost::iequals(val.first, "mqttsuffix")) {
			//assume prefix mqtt part is already set in this sensor. Just append suffix
			sensor.setMqtt(sensor.getMqtt() + val.second.data());
		} else if (boost::iequals(val.first, "minValues")) {
			sensor.setMinValues(stoull(val.second.data()));
		} else if (boost::iequals(val.first, ("id"))) {
			sensor.setPropertyId(static_cast<BACNET_PROPERTY_ID>(stoul(val.second.data())));
		} else if (boost::iequals(val.first, "default")) {
			//avoid unnecessary "Value not recognized" message
		} else {
			LOG(warning) << "  Value \"" << val.first << "\" not recognized. Omitting...";
		}
	}

	LOG(debug) << "  MQTTtopic:" << sensor.getMqtt();
	LOG(debug) << "  Interval : " << sensor.getInterval();
	LOG(debug) << "  minValues: " << sensor.getMinValues();
	LOG(debug) << "  instance : " << sensor.getDeviceInstance();
	LOG(debug) << "  objInst  : " << sensor.getObjectInstance();
	LOG(debug) << "  objType  : " << sensor.getObjectType();
	LOG(debug) << "  Property : " << sensor.getPropertyId();

169
	return true;
170
}