Commit 933559c8 authored by Micha Mueller's avatar Micha Mueller
Browse files

Add some file generating scripts to simplify writing of own plugins

parent 6880ac36
......@@ -356,6 +356,7 @@ Explanation of the values specific for the BACnet plugin:
| id | ID of the property to be read from the BACnet device-object. Assignment of numbers to properties is done according to the enum as defined in `bacenum.h`.
## Writing own plugins
Try out the `pluginGenerator/generatePlugin.sh` script!
TODO!
#### TODOS
......
#!/bin/sh
cat << EOF > ${PLUGIN_NAME}Configurator.cpp
/*
* ${PLUGIN_NAME}Configurator.cpp
*
* Created on: ${DATE}
* Author: ${AUTHOR}
*/
#include "${PLUGIN_NAME}Configurator.h"
${PLUGIN_NAME}Configurator::${PLUGIN_NAME}Configurator() {}
${PLUGIN_NAME}Configurator::~${PLUGIN_NAME}Configurator() {}
bool ${PLUGIN_NAME}Configurator::derivedReadConfig(boost::property_tree::iptree& cfg) {
/*
* TODO
* If neccessary, read in other plugin specific stuff
*/
//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()) {
${PLUGIN_NAME}SingleSensor* ${PLUGIN_NAME_LWC}Sensor = new ${PLUGIN_NAME}SingleSensor(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()) {
*${PLUGIN_NAME_LWC}Sensor = it->second;
${PLUGIN_NAME_LWC}Sensor->setName(sensor.second.data());
} else {
LOG(warning) << "Template sensor \"" << defaultS.get().data() << "\" not found! Using standard values.";
}
}
//read remaining values
if(readSensorBase(*${PLUGIN_NAME_LWC}Sensor, sensor.second)) {
_sensors.push_back(${PLUGIN_NAME_LWC}Sensor);
} else {
LOG(warning) << " Sensor \"" << sensor.second.data() << "\" has bad values! Ignoring...";
}
}
}
}
return true;
}
bool ${PLUGIN_NAME}Configurator::derivedReadSensorBase(${PLUGIN_NAME}SensorBase& sensor, boost::property_tree::iptree& config) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
/*
* TODO
* Read in plugin specific sensor attributes
*/
if (STRCMP(val, "mqttsuffix")) {
sensor.setMqtt(_mqttPrefix + val.second.data());
/* Example code:
} else if (STRCMP(val, ("stringAttribute"))) {
sensor.setStringAttribute(val.second.data());
} else if (STRCMP(val, "intAttribute")) {
sensor.setIntAttribute(stoi(val.second.data())); */
}
}
/*
* TODO
* Print the read in values for debugging
*/
/*
LOG(debug) << " stringAtt: " << sensor.getStringAttribute();
LOG(debug) << " intAtt : " << sensor.getIntAttribute();
*/
return true;
}
EOF
#!/bin/sh
cat << EOF > ${PLUGIN_NAME}Configurator.h
/*
* ${PLUGIN_NAME}Configurator.h
*
* Created on: ${DATE}
* Author: ${AUTHOR}
*/
#ifndef ${PLUGIN_NAME_UPC}_${PLUGIN_NAME_UPC}CONFIGURATOR_H_
#define ${PLUGIN_NAME_UPC}_${PLUGIN_NAME_UPC}CONFIGURATOR_H_
#include "../../headers/ConfiguratorTemplate.h"
#include "${PLUGIN_NAME}SingleSensor.h"
class ${PLUGIN_NAME}Configurator : public ConfiguratorTemplate<${PLUGIN_NAME}SensorBase, ${PLUGIN_NAME}SingleSensor> {
public:
${PLUGIN_NAME}Configurator();
virtual ~${PLUGIN_NAME}Configurator();
protected:
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 derivedReadSensorBase(${PLUGIN_NAME}SensorBase& sensor, boost::property_tree::iptree& config) override;
};
extern "C" ConfiguratorInterface* create() {
return new ${PLUGIN_NAME}Configurator;
}
extern "C" void destroy(ConfiguratorInterface* c) {
delete c;
}
#endif /* ${PLUGIN_NAME_UPC}_${PLUGIN_NAME_UPC}CONFIGURATOR_H_ */
EOF
#!/bin/sh
cat << EOF > ${PLUGIN_NAME}SensorBase.h
/*
* ${PLUGIN_NAME}SensorBase.h
*
* Created on: ${DATE}
* Author: ${AUTHOR}
*/
#ifndef ${PLUGIN_NAME_UPC}_${PLUGIN_NAME_UPC}SENSORBASE_H_
#define ${PLUGIN_NAME_UPC}_${PLUGIN_NAME_UPC}SENSORBASE_H_
#include "../../headers/SensorBase.h"
/*
* TODO
* Add plugin specific includes
*/
class ${PLUGIN_NAME}SensorBase : virtual public SensorBase {
public:
${PLUGIN_NAME}SensorBase(const std::string& name) :
SensorBase(name) {
/*
* TODO
* Initialize plugin specific attributes
*/
}
virtual ~${PLUGIN_NAME}SensorBase() {
/*
* TODO
* If necessary, deconstruct plugin specific attributes
*/
}
/*
* TODO
* Getters and Setters for plugin specific attributes
*/
protected:
/*
* TODO
* Add plugin specific attributes here
*/
};
#endif /* ${PLUGIN_NAME_UPC}_${PLUGIN_NAME_UPC}SENSORBASE_H_ */
EOF
#!/bin/sh
cat << EOF > ${PLUGIN_NAME}SingleSensor.cpp
/*
* ${PLUGIN_NAME}SingleSensor.cpp
*
* Created on: ${DATE}
* Author: ${AUTHOR}
*/
#include "${PLUGIN_NAME}SingleSensor.h"
#include "timestamp.h"
/*
* TODO
* Add additional required includes
*/
${PLUGIN_NAME}SingleSensor::${PLUGIN_NAME}SingleSensor(const std::string& name) :
SensorBase(name), ${PLUGIN_NAME}SensorBase(name), SingleSensor(name) {}
${PLUGIN_NAME}SingleSensor::~${PLUGIN_NAME}SingleSensor() {}
void ${PLUGIN_NAME}SingleSensor::start() {
if (_keepRunning) {
//we have been started already
LOG(info) << "Sensor " << _name << " already running.";
return;
}
/*
* TODO
* Start plugin specific stuff
*/
_keepRunning = 1;
_pendingTasks++;
_timer->async_wait(std::bind(&${PLUGIN_NAME}SingleSensor::readAsync, this));
LOG(info) << "Sensor " << _name << " started.";
}
void ${PLUGIN_NAME}SingleSensor::stop() {
_keepRunning = 0;
/*
* TODO
* Stop plugin specific stuff
*/
LOG(info) << "Sensor " << _name << " stopped.";
}
void ${PLUGIN_NAME}SingleSensor::read() {
reading_t reading;
reading.timestamp = getTimestamp();
try {
reading.value = /*
* TODO
* Plugin sensor read logic goes here
*/ 0;
storeReading(reading, _cacheIndex);
_cacheIndex = (_cacheIndex + 1) % _cacheSize;
#ifdef DEBUG
LOG(debug) << _name << ": \"" << reading.value << "\"";
#endif
} catch (const std::exception& e) {
LOG(error) << _name << " could not read value: " << e.what();
}
}
void ${PLUGIN_NAME}SingleSensor::readAsync() {
uint64_t now = getTimestamp();
read();
if (_timer && _keepRunning) {
uint64_t next = now + MS_TO_NS(_interval);
_timer->expires_at(timestamp2ptime(next));
_pendingTasks++;
_timer->async_wait(std::bind(&${PLUGIN_NAME}SingleSensor::readAsync, this));
}
_pendingTasks--;
}
EOF
#!/bin/sh
cat << EOF > ${PLUGIN_NAME}SingleSensor.h
/*
* ${PLUGIN_NAME}SingleSensor.h
*
* Created on: ${DATE}
* Author: ${AUTHOR}
*/
#ifndef ${PLUGIN_NAME_UPC}_${PLUGIN_NAME_UPC}SINGLESENSOR_H_
#define ${PLUGIN_NAME_UPC}_${PLUGIN_NAME_UPC}SINGLESENSOR_H_
#include "${PLUGIN_NAME}SensorBase.h"
#include "../../headers/SingleSensor.h"
class ${PLUGIN_NAME}SingleSensor : public ${PLUGIN_NAME}SensorBase, public SingleSensor {
public:
${PLUGIN_NAME}SingleSensor(const std::string& name);
virtual ~${PLUGIN_NAME}SingleSensor();
void start() override;
void stop() override;
private:
void read() override;
void readAsync() override;
};
#endif /* ${PLUGIN_NAME_UPC}_${PLUGIN_NAME_UPC}SINGLESENSOR_H_ */
EOF
#!/bin/sh
cat << EOF > ${PLUGIN_NAME}.conf
;comments in config files are indicated by a semicolon
global {
mqttPrefix /FF112233445566778899AABBFFFF
;add here other global attributes for your plugin
}
sensorTemplates {
;define here template sensors
sensor temp1 {
interval 1000
minValues 3
pluginAtt 1234
}
}
sensors {
;define here the actual sensors for your plugin
sensor sens1 {
default temp1
mqttsuffix 0001
;add other attributes your plugin requires for a sensor
}
}
EOF
#!/bin/sh
# Only plugin generation without groups supported currently!
# TODO generate stuff for config and Makefile
# first check input parameters
if [ $# -ne 1 ]
then
echo "False number of arguments!"
echo "Usage:"
echo "./generatePlugin.sh pluginName"
exit 1
fi
# Set variables
DATE=`date '+%d.%m.%Y'`
AUTHOR="Your name goes here!"
PLUGIN_NAME=$1
PLUGIN_NAME_UPC=`echo $PLUGIN_NAME | tr 'a-z' 'A-Z'`
PLUGIN_NAME_LWC=`echo $PLUGIN_NAME | tr 'A-Z' 'a-z'`
if [ -e ${PLUGIN_NAME_LWC} ]
then
echo "${PLUGIN_NAME_LWC}/ directory already present"
else
echo "Creating ${PLUGIN_NAME_LWC}/ directory"
mkdir ${PLUGIN_NAME_LWC}
fi
cd ${PLUGIN_NAME_LWC}
# Generate ...SensorBase.h
echo "Generating ${PLUGIN_NAME}SensorBase.h ..."
. ../SensorBase_h.sh
# Generate ...SingleSensor.h
echo "Generating ${PLUGIN_NAME}SingleSensor.h ..."
. ../SingleSensor_h.sh
# Generate ...SingleSensor.cpp
echo "Generating ${PLUGIN_NAME}SingleSensor.cpp ..."
. ../SingleSensor_cpp.sh
# Generate ...Configurator.h
echo "Generating ${PLUGIN_NAME}Configurator.h ..."
. ../Configurator_h.sh
# Generate ...Configurator.cpp
echo "Generating ${PLUGIN_NAME}Configurator.cpp ..."
. ../Configurator_cpp.sh
# Generate Makefile code
echo "Generating code for Makefile ..."
. ../makefile.sh
# Generate ....conf
echo "Generating ${PLUGIN_NAME}.conf ..."
. ../config.sh
echo ""
echo "Plugin generator completed succefully"
echo ""
echo "Further steps to take from here:"
echo "* The generated files should go to their appropriate location:"
echo " - the .conf goes to the other config files in config/"
echo " - the source files should go in their own plugin directory at src/sensors/"
echo " - copy required lines into Makefile as instructed in appendToMakefile.txt"
echo "* Complete the code in the generated source files. The TODOs are a good starting point, but you"
echo " may need to make even more changes (and create more source files) for your plugin to work"
echo "* Extend the .conf and Makefile as required."
#!/bin/sh
cat << EOF > appendToMakefile.txt
Append to PLUGINS_BASE variable: libdcdbplugin_${PLUGIN_NAME_LWC}
Append at end of Makefile:
libdcdbplugin_${PLUGIN_NAME_LWC}.\$(LIBEXT): src/sensors/${PLUGIN_NAME_LWC}/${PLUGIN_NAME}SingleSensor.o src/sensors/${PLUGIN_NAME_LWC}/${PLUGIN_NAME}Configurator.o
\$(CXX) \$(LIBFLAGS)\$@ -o \$@ $^ -L\$(DCDBDEPLOYPATH)/lib/ -lboost_log -lboost_system
NOTE: Probably you will have to append further libraries to the linker for your plugin to compile
EOF
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment