diff --git a/.gitattributes b/.gitattributes
index 895f7b97edae90dab83135bf125de428053be93a..13bce7cc5d0b344ad0dcab25285e6326b8149dad 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1730,6 +1730,7 @@ LCS/WinCCWrapper/include/CMakeLists.txt -text
 LCS/WinCCWrapper/include/WinCCManager.h -text
 LCS/WinCCWrapper/include/WinCCResources.h -text
 LCS/WinCCWrapper/include/WinCCWrapper.h -text
+LCS/WinCCWrapper/include/exceptions.h -text
 LCS/WinCCWrapper/src/CMakeLists.txt -text
 LCS/WinCCWrapper/src/ConnectWaitForAnswer.cc -text
 LCS/WinCCWrapper/src/ConnectWaitForAnswer.h -text
@@ -1738,8 +1739,10 @@ LCS/WinCCWrapper/src/WinCCResources.cc -text
 LCS/WinCCWrapper/src/WinCCWrapper.cc -text
 LCS/WinCCWrapper/src/WinCCWrapper_boost_python.cc -text
 LCS/WinCCWrapper/src/__init__.py -text
+LCS/WinCCWrapper/src/exceptions.h -text
 LCS/WinCCWrapper/test/CMakeLists.txt -text
 LCS/WinCCWrapper/test/WinCCGet.cc -text
+LCS/WinCCWrapper/test/WinCCQuery.cc -text
 LCS/WinCCWrapper/test/WinCCSet.cc -text
 LCS/WinCCWrapper/test/mock.py -text
 LCS/doc/package.dox -text
diff --git a/LCS/WinCCWrapper/CMakeLists.txt b/LCS/WinCCWrapper/CMakeLists.txt
index 84b66b8cfbc355c245611b34f932984b92be3958..d00636a4e7e1406b9101c7420197ba7662c25c4a 100644
--- a/LCS/WinCCWrapper/CMakeLists.txt
+++ b/LCS/WinCCWrapper/CMakeLists.txt
@@ -4,7 +4,7 @@ lofar_package(WinCCWrapper 1.0 )
 include(LofarFindPackage)
 
 #hard-coded path where wincc api can be found on build systems
-set(WINCC_ROOT_DIR /opt/WinCC_OA/3.15 CACHE PATH "root dir where the WinCC_OA api can be found")
+#set(WINCC_ROOT_DIR /opt/WinCC_OA/3.15 CACHE PATH "root dir where the WinCC_OA api can be found")
 lofar_find_package(WINCC)
 
 IF(WINCC_FOUND)
diff --git a/LCS/WinCCWrapper/include/CMakeLists.txt b/LCS/WinCCWrapper/include/CMakeLists.txt
index 9341a3420be5b55ea0c821bc02652445231d2430..48366da002dc0da6ca064036ffaf96e0f46532a4 100644
--- a/LCS/WinCCWrapper/include/CMakeLists.txt
+++ b/LCS/WinCCWrapper/include/CMakeLists.txt
@@ -1,5 +1,5 @@
 # Create symbolic link to include directory.
-execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink 
+execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink
   ${CMAKE_CURRENT_SOURCE_DIR}
   ${CMAKE_BINARY_DIR}/include/${PACKAGE_NAME})
 
@@ -8,4 +8,5 @@ install(FILES
   WinCCManager.h
   WinCCResources.h
   WinCCWrapper.h
+  exceptions.h
   DESTINATION include/${PACKAGE_NAME})
diff --git a/LCS/WinCCWrapper/include/WinCCManager.h b/LCS/WinCCWrapper/include/WinCCManager.h
index 69e70cbb947cf731c2a3bbf24224aa4ed7c16b5c..c29d37cefaad6c4d20936064db3ae4c074cf68b4 100644
--- a/LCS/WinCCWrapper/include/WinCCManager.h
+++ b/LCS/WinCCWrapper/include/WinCCManager.h
@@ -31,6 +31,7 @@
 #include <Variable.hxx>
 
 #include <boost/python.hpp>
+#include <boost/any.hpp>
 
 namespace LOFAR {
     namespace WINCCWRAPPER {
@@ -41,7 +42,6 @@ class WinCCManager : public Manager
 public:
     //! default constructor
     WinCCManager();
-
     //! run the manager, connect to the running wincc instance.
     void run();
     //! exit the manager, disconnect from the running wincc instance.
@@ -49,8 +49,15 @@ public:
 
     //! subscribe for changes on this list of datapoints. Whenever any of these datapoints changes value, the callback function from set_connect_datapoints_callback is called with the changed datapoint name and value.
     void connect_datapoints(const std::vector<std::string> &data_points);
+    //! subscribe for changes on this list of datapoints. Whenever any of these datapoints change all the values from these datapoints gets returned in one call.
+    void connect_datapoints_multiple(const std::vector<std::string> &data_points);
+    //! unsubscribe for changes on this list of datapoints.
+    void disconnect_datapoints(const std::vector<std::string> &data_points);
+    //! provide your callback function which is called whenever any of the connected datapoints is changed.
+    void set_connect_datapoints_callback(std::function<void(std::string name, std::string value)> callback_functor) {callback = callback_functor;};
     //! provide your callback function which is called whenever any of the connected datapoints is changed.
-    void set_connect_datapoints_callback(std::function<void(std::string name, std::string value)> callback) {callback = callback;};
+    void set_connect_datapoints_callback(std::function<void(std::map<std::string, std::string>)> callback_functor) {callback_multi = callback_functor;};
+
 
     //! set the datapoint with given name to the given value, returns true upon success.
     /*! set the datapoint with given name to the given value
@@ -75,7 +82,10 @@ public:
     bool get_datapoint(const std::string &name, boost::python::list &value);
     //! get the datapoint with the given name and return it's std::vector<int> value in parameter value. returns true upon success.
     bool get_datapoint(const std::string &name, std::vector<int> &value);
-
+    //! get the datapoint with a any type
+    bool get_datapoint_any(const std::string &datapoint_name, boost::any &value);
+    //! set the datapoint with a any type
+    bool set_datapoint_any(const std::string &datapoint_name, const boost::any &value);
     //! mark the datapoint with given name valid. returns true upon success.
     bool set_datapoint_valid(const std::string &name) { return set_datapoint_validity(name, true, nullptr); }
     //! mark the datapoint with given name invalid. returns true upon success.
@@ -83,24 +93,32 @@ public:
     //! set the datapoint with given name valid/invalid. returns true upon success.
     bool set_datapoint_validity(const std::string &name, bool validity, const Variable *value=nullptr);
 
+    bool get_query(const std::string &query, std::vector<std::vector<std::string>> & result);
     //! handle signals to exit nicely
     virtual void signalHandler(int sig);
+
+    void wait_for_event(long sec, long microSec);
+
 private:
     void init();
 
     friend class ConnectWaitForAnswer;
 
     void handle_hotlink(const std::string &name, const std::string &value);
+    void handle_hotlink(const std::map<std::string, std::string> &);
+
     void handle_get(const std::string &name, Variable *&value);
 
     bool request_datapoint(const std::string &name);
 
+    bool request_query_result(const std::string &query, PVSSulong & identifier);
     template <typename Tval>
     bool _get_datapoint(const std::string &name, Tval &value);
 
     template <typename Tval>
     bool _get_datapoint(const std::string &name, Tval *value);
 
+
     bool get_datapoint_variable(const std::string &name, Variable *&value);
 
     bool has_received_variable(const std::string &name);
@@ -109,6 +127,7 @@ private:
 
     volatile static bool doExit;
     std::function<void(std::string name, std::string value)> callback;
+    std::function<void(std::map<std::string, std::string>)> callback_multi;
     std::mutex mtx;
     std::condition_variable cv;
     std::map<std::string, Variable *> values;
diff --git a/LCS/WinCCWrapper/include/WinCCResources.h b/LCS/WinCCWrapper/include/WinCCResources.h
index 552e9fcf771938a27fdad189e915440db5f91500..b387368eb42f7c379894621960b07de3db0ea905 100644
--- a/LCS/WinCCWrapper/include/WinCCResources.h
+++ b/LCS/WinCCWrapper/include/WinCCResources.h
@@ -27,9 +27,12 @@ namespace LOFAR {
 class WinCCResources
 {
 public:
-    WinCCResources(const std::string &projec_name);
+    WinCCResources(const std::string &project_name);
+
+    WinCCResources(const std::string &program_name, const std::string &project_name, const int num);
 private:
-    void init(const std::string &projec_name);
+    void init(const std::string &project_name);
+    void init(const std::string &program_name, const std::string &project_name, const int num);
 };
 
     } // namespace WINCCWRAPPER
diff --git a/LCS/WinCCWrapper/include/WinCCWrapper.h b/LCS/WinCCWrapper/include/WinCCWrapper.h
index 26fa060d6064ee4fcff3f620e44b86a90c52327a..4e57aa17166f24a9fc34c283d9dce20047f61ee1 100644
--- a/LCS/WinCCWrapper/include/WinCCWrapper.h
+++ b/LCS/WinCCWrapper/include/WinCCWrapper.h
@@ -21,6 +21,7 @@
 #define WINCCSERVICES_WINCC_WRAPPER_H
 
 #include <string>
+#include <boost/variant.hpp>
 #include <vector>
 #include <ctime>
 #include <functional>
@@ -29,6 +30,7 @@
 #include "WinCCManager.h"
 
 #include <boost/python.hpp>
+#include <boost/any.hpp>
 
 namespace LOFAR {
     namespace WINCCWRAPPER {
@@ -40,6 +42,9 @@ class WinCCWrapper
 public:
     //! default constructor
     WinCCWrapper(const std::string &project_name);
+
+    //! default constructor
+    WinCCWrapper(const std::string &program_name, const std::string &project_name, const int num);
     //! disconnect from the running wincc instance.
     void exit();
     //! connect to the running wincc instance.
@@ -47,14 +52,21 @@ public:
 
     //! subscribe for changes on this list of datapoints. Whenever any of these datapoints changes value, the callback function from set_connect_datapoints_callback is called with the changed datapoint name and value.
     void connect_datapoints(const std::vector<std::string> &data_points);
+    //! subscribe for changes on this list of datapoints. Whenever any of these datapoints changes value, the callback function from set_connect_datapoints_callback is called with all the specified values.
+    void connect_datapoints_multi(const std::vector<std::string> &data_points);
+
+    //! unsubscribe for changes on the given list of datapoints.
+    void disconnect_datapoints(const std::vector<std::string> &data_points);
     //! provide your callback function which is called whenever any of the connected datapoints is changed.
     void set_connect_datapoints_callback(std::function<void(std::string name, std::string value)> callback);
+    //! provide your callback function which is called whenever any of the connected datapoints is changed. It returns all the specified datapoints even if only one changes.
+    void set_connect_datapoints_callback(std::function<void(std::map<std::string, std::string>)> callback);
 
     //! set the datapoint with given name to the given int value, mark it valid/invalid, returns true upon success.
     bool set_datapoint(const std::string &name, int value, bool valid=true);
     //! set the datapoint with given name to the given boost::python::list value, mark it valid/invalid, returns true upon success.
     bool set_datapoint(const std::string &name, boost::python::list &value, bool valid=true);
-    //! set the datapoint with given name to the given boost::python::tuple value, mark it valid/invalid, returns true upon success.  
+    //! set the datapoint with given name to the given boost::python::tuple value, mark it valid/invalid, returns true upon success.
     bool set_datapoint(const std::string &name, boost::python::tuple &value, bool valid=true);
     //! set the datapoint with given name to the given std::vector<int> value, mark it valid/invalid, returns true upon success.
     bool set_datapoint(const std::string &name, std::vector<int> &value, bool valid=true);
@@ -70,11 +82,14 @@ public:
     //! set the datapoint with given name to the given time_t value, mark it valid/invalid, returns true upon success.
     bool set_datapoint_time(const std::string &name, time_t value, bool valid=true);
 
+    bool set_datapoint_any(const std::string &name, boost::any value);
     //! mark the datapoint with given name valid.
     bool set_datapoint_valid(const std::string &name);
     //! mark the datapoint with given name invalid.
     bool set_datapoint_invalid(const std::string &name);
 
+    //! provide the boost::any for the given datapoint name
+    boost::any get_datapoint_any (const std::string &name);
     //! get the datapoint with the given name and return it as an int value if possible, otherwise an exception is raised.
     int get_datapoint_int(const std::string &name);
     //! get the datapoint with the given name and return it as a long value if possible, otherwise an exception is raised.
@@ -88,11 +103,17 @@ public:
     //! get the datapoint with the given name and return it as a time_t value if possible, otherwise an exception is raised.
     time_t get_datapoint_time(const std::string &name);
     //! get the datapoint with the given name and return it as a boost::python::list value if possible, otherwise an exception is raised.
-    boost::python::list get_datapoint_list(const std::string &name); 
+    boost::python::list get_datapoint_list(const std::string &name);
+    //! get the datapoint last set time
+    time_t get_datapoint_set_time(const std::string &name);
     //! get the datapoint with the given name and return it as a std::vector<int> value if possible, otherwise an exception is raised.
     //! this method is used in the WinCCGet test
     std::vector<int> get_datapoint_vector(const std::string &name);
+    //! get the datapoint with the given name and return it as a std::vector<std::string> value.
+    std::vector<std::string> get_datapoint_vector_string(const std::string &name);
 
+    std::string get_formatted_datapoint(const std::string &name);
+    void wait_for_event(long sec, long microSec);
 private:
     // get_datapoint
     template <typename T>
diff --git a/LCS/WinCCWrapper/include/exceptions.h b/LCS/WinCCWrapper/include/exceptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..998ab30809e845243ed043bdc8159bbb7cd7a5bd
--- /dev/null
+++ b/LCS/WinCCWrapper/include/exceptions.h
@@ -0,0 +1,23 @@
+#ifndef WINCC_EXCEPTIONS
+#define WINCC_EXCEPTIONS
+
+namespace LOFAR{
+namespace WINCCWRAPPER{
+
+class DatapointNameNotFound : public std::exception
+{
+private:
+    std::string message;
+public:
+    DatapointNameNotFound(const std::string & datapointName):
+        message{"Datapoint " + datapointName + " not found"}{}
+	const char * what () const throw ()
+    {
+    	return message.c_str();
+    }
+};
+
+}
+}
+
+#endif
diff --git a/LCS/WinCCWrapper/src/ConnectWaitForAnswer.cc b/LCS/WinCCWrapper/src/ConnectWaitForAnswer.cc
index 767ea576d761ca1ee4e99202ba2f07af82c3ba11..b35c3cfe0396b49532f141ca1161d76e17e9a9aa 100644
--- a/LCS/WinCCWrapper/src/ConnectWaitForAnswer.cc
+++ b/LCS/WinCCWrapper/src/ConnectWaitForAnswer.cc
@@ -25,13 +25,22 @@ namespace LOFAR {
 
 using namespace std;
 
+ConnectWaitForAnswer::ConnectWaitForAnswer(const bool handle_multi): HotLinkWaitForAnswer{}, multi{handle_multi}{
+
+}
+
+ConnectWaitForAnswer::ConnectWaitForAnswer(): HotLinkWaitForAnswer{}{
+
+}
+
 void ConnectWaitForAnswer::hotLinkCallBack(DpMsgAnswer &answer)
 {
+    const std::string answer_id{std::to_string(answer.getAnswerId())};
     for (AnswerGroup *grpPtr = answer.getFirstGroup(); grpPtr; grpPtr = answer.getNextGroup())
     {
         if (grpPtr->getError())
         {
-            cout << "Error!" << endl;
+            cout <<grpPtr->getError()->toString()<< endl;
         }
         else
         {
@@ -42,6 +51,8 @@ void ConnectWaitForAnswer::hotLinkCallBack(DpMsgAnswer &answer)
                 if(varPtr)
                 {
                     string name = get_datapoint_name(item);
+                    if(name.compare("") == 0) name += answer_id;
+
                     Variable *value = varPtr->clone(); //WinCCManager should delete cloned pointer
 
     	            ((WinCCManager *) Manager::getManPtr())->handle_get(name, value);
@@ -52,6 +63,14 @@ void ConnectWaitForAnswer::hotLinkCallBack(DpMsgAnswer &answer)
 }
 
 void ConnectWaitForAnswer::hotLinkCallBack(DpHLGroup &group)
+{
+    if(multi){
+        handle_multi(group);
+    }else{
+        handle_one_by_one(group);
+    }
+}
+void ConnectWaitForAnswer::handle_one_by_one(DpHLGroup &group)
 {
     for (DpVCItem *item = group.getFirstItem(); item; item = group.getNextItem())
     {
@@ -59,6 +78,25 @@ void ConnectWaitForAnswer::hotLinkCallBack(DpHLGroup &group)
     }
 }
 
+void ConnectWaitForAnswer::handle_multi(DpHLGroup &group)
+{
+
+    std::map<std::string, std::string> values;
+    for (DpVCItem *item = group.getFirstItem(); item; item = group.getNextItem())
+    {
+        Variable *varPtr = item->getValuePtr();
+
+        if (varPtr){
+            const string name = get_datapoint_name(item);
+            const string value = varPtr->formatValue().c_str();
+
+            values[name] = value;
+        }
+    }
+    ((WinCCManager *) Manager::getManPtr())->handle_hotlink(values);
+}
+
+
 void ConnectWaitForAnswer::handle_group_item(const DpVCItem* const item)
 {
     Variable *varPtr = item->getValuePtr();
@@ -66,6 +104,7 @@ void ConnectWaitForAnswer::handle_group_item(const DpVCItem* const item)
     if (varPtr)
     {
         string name = get_datapoint_name(item);
+
         string value = varPtr->formatValue().c_str();
 
     	((WinCCManager *) Manager::getManPtr())->handle_hotlink(name, value);
diff --git a/LCS/WinCCWrapper/src/ConnectWaitForAnswer.h b/LCS/WinCCWrapper/src/ConnectWaitForAnswer.h
index 28dd3f0138a5c84e25374ade4ee2bea51ad9745a..dba485153cad7e3848ec381da58588b903639bb6 100644
--- a/LCS/WinCCWrapper/src/ConnectWaitForAnswer.h
+++ b/LCS/WinCCWrapper/src/ConnectWaitForAnswer.h
@@ -32,12 +32,18 @@ namespace LOFAR {
 class ConnectWaitForAnswer : public HotLinkWaitForAnswer
 {
 public:
+    ConnectWaitForAnswer();
+    ConnectWaitForAnswer(const bool handle_multi);
     using HotLinkWaitForAnswer::hotLinkCallBack;
     virtual void hotLinkCallBack(DpMsgAnswer &answer);
     virtual void hotLinkCallBack(DpHLGroup &group);
 private:
+    bool multi;
+    void handle_one_by_one(DpHLGroup &group);
+    void handle_multi(DpHLGroup &group);
     void handle_group_item(const DpVCItem* const item);
     std::string get_datapoint_name(const DpVCItem* const item);
+
 };
 
     } // namespace WINCCWRAPPER
diff --git a/LCS/WinCCWrapper/src/WinCCManager.cc b/LCS/WinCCWrapper/src/WinCCManager.cc
index 6aa6c34b42ef58025ee2c2e37199c6820783e7f0..4dd1eaff04e8bfa83054f5a10332b49ab2f33a3d 100644
--- a/LCS/WinCCWrapper/src/WinCCManager.cc
+++ b/LCS/WinCCWrapper/src/WinCCManager.cc
@@ -34,10 +34,18 @@
 #include <TextVar.hxx>
 #include <DynVar.hxx>
 #include <DynPtrArray.hxx>
+#include <Resources.hxx>
 #include <cassert>
 #include <vector>
 #include <boost/python.hpp>
 
+#include <Manager.hxx>
+#include <DpElement.hxx>
+#include <DpIdentification.hxx>
+#include <DpIdentificationResultType.hxx>
+#include <boost/any.hpp>
+#include <exceptions.h>
+
 namespace LOFAR {
     namespace WINCCWRAPPER {
 
@@ -100,12 +108,77 @@ void WinCCManager::connect_datapoints(const std::vector<std::string> &dataPoints
     }
 }
 
+void WinCCManager::connect_datapoints_multiple(const std::vector<std::string> &dataPoints)
+{
+
+    DpIdentList  dpList;
+    for(vector<string>::const_iterator it = dataPoints.begin(); it != dataPoints.end(); it++)
+    {
+        DpIdentifier dpIdConnect;
+
+        if (Manager::getId(it->c_str(), dpIdConnect) == PVSS_FALSE)
+        {
+            // This name was unknown
+            ErrHdl::error(ErrClass::PRIO_SEVERE,
+                          ErrClass::ERR_PARAM,
+                          ErrClass::UNEXPECTEDSTATE,
+                          "PublishManager",
+                          "connect_datapoints",
+                          CharString("Datapoint ") + CharString(it->c_str()) +
+                          CharString(" missing"));
+        }
+        else
+        {
+            dpList.append(dpIdConnect);
+
+        }
+    }
+    // We give the dpConnect a nice naked pointer because it will delete it when the manager stops.
+    HotLinkWaitForAnswer* wait = new ConnectWaitForAnswer(true);
+    Manager::dpConnect(dpList, wait);
+}
+
+
+void WinCCManager::disconnect_datapoints(const std::vector<std::string> &dataPoints)
+{
+    for(vector<string>::const_iterator it = dataPoints.begin(); it != dataPoints.end(); it++)
+    {
+        DpIdentifier dpIdConnect;
+
+        if (Manager::getId(it->c_str(), dpIdConnect) == PVSS_FALSE)
+        {
+            // This name was unknown
+            ErrHdl::error(ErrClass::PRIO_SEVERE,
+                          ErrClass::ERR_PARAM,
+                          ErrClass::UNEXPECTEDSTATE,
+                          "PublishManager",
+                          "connect_datapoints",
+                          CharString("Datapoint ") + CharString(it->c_str()) +
+                          CharString(" missing"));
+        }
+        else
+        {
+            // We give the dpConnect a nice naked pointer because it will delete it when the manager stops.
+            HotLinkWaitForAnswer* wait = new ConnectWaitForAnswer();
+            Manager::dpDisconnect(dpIdConnect, wait);
+        }
+    }
+}
+
 bool WinCCManager::set_datapoint(const std::string &name, const Variable &value, bool valid)
 {
     //reuse the set_datapoint_validity, and explicitly set the value to the given value
     return set_datapoint_validity(name, valid, &value);
 }
 
+
+// request the query (async). is called by _get_query which makes it blocking (synchronous) by waiting for the answer.
+bool WinCCManager::request_query_result(const std::string &query, PVSSulong & identifier)
+{
+    HotLinkWaitForAnswer* wait = new ConnectWaitForAnswer();
+    return (PVSS_TRUE == Manager::dpQuery(query.c_str(), identifier, wait));
+}
+
 // request the datapoint (async). is called by _get_datapoint which makes it blocking (synchronous) by waiting for the answer.
 bool WinCCManager::request_datapoint(const std::string &name)
 {
@@ -333,6 +406,72 @@ Variable::ConvertResult convert(Variable *var, struct tm &value, Variable *&conv
     return cr;
 }
 
+boost::any convert_any(Variable * variable, boost::any & value){
+    Variable * converted_variable{nullptr};
+    switch(variable->isA()){
+        case VariableType::INTEGER_VAR:{
+            int casted_variable;
+            convert(variable, casted_variable, converted_variable);
+            value = casted_variable;
+
+            break;
+        }
+        case VariableType::FLOAT_VAR: {
+            float casted_variable;
+            convert(variable, casted_variable, converted_variable);
+            value = casted_variable;
+
+            break;
+        }
+        case VariableType::TEXT_VAR: {
+            std::string casted_variable;
+            convert(variable, casted_variable, converted_variable);
+            value = casted_variable;
+
+            break;
+        }
+        case VariableType::LONG_VAR:{
+            // Find the wincc guy who though this out
+            long casted_variable;
+            convert(variable, casted_variable, converted_variable);
+            value = casted_variable;
+
+            break;
+        }
+        case VariableType::BIT_VAR: {
+            bool casted_variable;
+            convert(variable, casted_variable, converted_variable);
+            value = casted_variable;
+
+            break;
+        }
+        case VariableType::TIME_VAR: {
+            time_t casted_variable;
+            convert(variable, casted_variable, converted_variable);
+            value = casted_variable;
+
+            break;
+        }
+        case VariableType::ANYTYPE_VAR: {
+            const AnyTypeVar * converted_var{static_cast<AnyTypeVar*>(variable)};
+            convert_any(converted_var->getVar(), value);
+            break;
+        }
+        case VariableType::DPIDENTIFIER_VAR: {
+            value = std::string{variable->formatValue().c_str()};
+            break;
+        }
+        default:
+            CharString value_str = variable->formatValue();
+            std::cerr<<value_str;
+            std::cerr<<"Datapoint type still not supported:  "<<std::hex<<variable->isA()<<std::endl;
+            value = std::string{value_str.c_str()};
+    }
+
+    if(converted_variable != nullptr) delete converted_variable;
+    return true;
+}
+
 //internal generic method to get the typed (Tval) value of a datapoint
 //used by the public strictly typed methods
 template <typename Tval>
@@ -355,6 +494,42 @@ bool WinCCManager::_get_datapoint(const std::string &name, Tval &value)
     return false;
 }
 
+bool convert_to_vector2(Variable * variable, std::vector<std::vector<std::string>> & result){
+    if(variable->isA(VariableType::DYN_VAR)){
+        const DynVar * rows{static_cast<DynVar *>(variable)};
+        for(DynPtrArrayIndex i=0; i < rows->getNumberOfItems(); i++){
+            const DynVar * row{static_cast<DynVar *>(rows->getAt(i))};
+            std::vector<std::string> * current_row{new std::vector<std::string>{}};
+            Variable * column{static_cast<DynVar *>(row->getNext())};
+            while(column){
+                current_row->push_back(column->formatValue().c_str());
+                column = static_cast<DynVar *>(row->getNext());
+            }
+            result.push_back(*current_row);
+            row = static_cast<DynVar *>(rows->getNext());
+        }
+        return true;
+    }
+    return false;
+}
+
+//internal generic method to query a set of WinCC data points. Since the type is not previously know
+bool WinCCManager::get_query(const std::string &query, std::vector<std::vector<std::string>> & result){
+    Variable * variable_value = nullptr;
+    PVSSulong identifier;
+    if(request_query_result(query, identifier))
+    {
+        std::string identifier_str{std::to_string(identifier)};
+        if(wait_for_received_variable(identifier_str, 1000)) {
+            if(get_received_variable(identifier_str, variable_value)) {
+                convert_to_vector2(variable_value, result);
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
 
 //below, a few strictly type methods for get_datapoint are defined
 //they just call the templated _get_datapoint, so why not just use the one and only templated method?
@@ -401,10 +576,11 @@ bool WinCCManager::get_datapoint(const std::string &name, std::vector<int> &valu
     return _get_datapoint(name, value);
 }
 
+
 bool WinCCManager::set_datapoint_validity(const std::string &name, bool validity, const Variable *value)
 {
     DpIdentifier dpId;
-    
+
     if (Manager::getId(name.c_str(), dpId) == PVSS_FALSE)
     {
         // This name was unknown.
@@ -434,8 +610,48 @@ bool WinCCManager::set_datapoint_validity(const std::string &name, bool validity
             infoBits.set(DriverBits::DRV_VALID_INVALID);
         }
 
-        DrvManager *drvman = DrvManager::getSelfPtr();
-        drvman ->sendVCMsg(dpId, value!=NULL ? *value : *last_known_value, now, infoBits);
+        // get VariableType from DpIdentifier
+        //   assign values
+        VariableType dpId_VariableType;
+        DpElementType dpId_ElementType;
+
+        DpIdentification temp_dpId;  // make a temp dpId to use the 'getElementType' method
+        DpIdentificationResult dir = temp_dpId.getElementType(dpId, dpId_ElementType);
+
+        //   check that the dpIdResult is OK
+        if(DpIdentificationResult::DpIdentOK == dir) {
+            dpId_VariableType = DpElement::getVariableType(dpId_ElementType);
+        }
+        else {
+            return false;
+        }
+
+        // check that the VariableType of the datapoint identifier matches the VariableType of the value given.
+        // if not, convert value to the appropriate datapoint type
+        if (value->isA() != dpId_VariableType){
+
+            VariablePtr converted_var = NULL;
+            Variable::ConvertResult cr = value->convert(dpId_VariableType, converted_var);
+
+            // if conversion succeeds, send the converted var
+            if(Variable::ConvertResult::OK == cr) {
+                DrvManager *drvman = DrvManager::getSelfPtr();
+                drvman ->sendVCMsg(dpId, converted_var!=NULL ? *converted_var : *last_known_value, now, infoBits);
+                delete converted_var;  //delete it, since it was a newly created variable in var->convert
+            }
+
+            // Either 'out_of_bounds' error or 'conv_not_defined' error in converting
+            else {
+                delete converted_var;  //delete it, since it was a newly created variable in var->convert
+                return false;
+            }
+        }
+
+        // no need for conversion
+        else {
+            DrvManager *drvman = DrvManager::getSelfPtr();
+            drvman ->sendVCMsg(dpId, value!=NULL ? *value : *last_known_value, now, infoBits);
+        }
 
         //process, wait max 10 ms
         long sec=0, usec=10000;
@@ -472,6 +688,10 @@ void WinCCManager::run()
     }
 }
 
+void WinCCManager::wait_for_event(long sec, long microSec){
+    dispatch(sec, microSec);
+}
+
 void WinCCManager::exit()
 {
     Manager::exit(0);
@@ -485,6 +705,14 @@ void WinCCManager::handle_hotlink(const std::string &name, const std::string &va
     }
 }
 
+void WinCCManager::handle_hotlink(const std::map<std::string, std::string> & values)
+{
+    if(callback_multi)
+    {
+        callback_multi(values);
+    }
+}
+
 void WinCCManager::signalHandler(int sig)
 {
     if ((sig == SIGINT) || (sig == SIGTERM))
@@ -497,6 +725,81 @@ void WinCCManager::signalHandler(int sig)
     }
 }
 
+bool WinCCManager::set_datapoint_any(const std::string &datapoint_name, const boost::any &value){
+    Variable * variable{nullptr};
+
+    if(get_datapoint_variable(datapoint_name, variable)){
+        switch(variable->isA()){
+            case VariableType::INTEGER_VAR: {
+                    IntegerVar converted_value{boost::any_cast<int>(value)};
+                    set_datapoint(datapoint_name, converted_value);
+                    break;
+                }
+            case VariableType::FLOAT_VAR: {
+                    FloatVar converted_value{boost::any_cast<float>(value)};
+                    set_datapoint(datapoint_name, converted_value);
+                    break;
+                }
+            case VariableType::TEXT_VAR: {
+                    TextVar converted_value{CharString(boost::any_cast<std::string>(value).c_str())};
+                    set_datapoint(datapoint_name, converted_value);
+                    break;
+                }
+            case VariableType::LONG_VAR:{
+                    LongVar converted_value{boost::any_cast<long>(value)};
+                    set_datapoint(datapoint_name, converted_value);
+
+                    break;
+                }
+            case VariableType::BIT_VAR: {
+                    BitVar converted_value{boost::any_cast<bool>(value)};
+                    set_datapoint(datapoint_name, converted_value);
+
+                    break;
+                }
+            case VariableType::TIME_VAR: {
+                    TimeVar converted_value(0,0);
+                    converted_value.setSeconds(boost::any_cast<time_t>(value));
+                    set_datapoint(datapoint_name, converted_value);
+
+                    break;
+                }
+            default:
+                std::cerr<<"Datapoint type still not supported:  "<<std::hex<<variable->isA()<<std::endl;
+                return false;
+        }
+    }else{
+        return false;
+    }
+
+    return true;
+}
+
+bool WinCCManager::get_datapoint_any(const std::string &datapoint_name, boost::any & value){
+    // Yeah I know... WinCC API is getting a &* to allocate the memory space...
+    Variable * variable{nullptr};
+    bool returnValue{true};
+
+    if(!get_datapoint_variable(datapoint_name, variable)){
+        // This name was unknown.
+        ErrHdl::error(ErrClass::PRIO_SEVERE,
+                      ErrClass::ERR_PARAM,
+                      ErrClass::UNEXPECTEDSTATE,
+                      Resources::getProgName(),
+                      "get_datapoint",
+                      CharString("Datapoint ") + CharString(datapoint_name.c_str()) +
+                      CharString(" missing"));
+        throw DatapointNameNotFound{datapoint_name};
+    }
+
+    convert_any(variable, value);
+
+    if(variable != nullptr) delete variable;
+
+    return returnValue;
+
+}
+
     } // namespace WINCCWRAPPER
 } // namespace LOFAR
 
diff --git a/LCS/WinCCWrapper/src/WinCCResources.cc b/LCS/WinCCWrapper/src/WinCCResources.cc
index 5eb7dbf8d1e3935abb068f6aa843514ba7b1c84a..a35accb448a859744f62a74adeeb8755ad2bc5f7 100644
--- a/LCS/WinCCWrapper/src/WinCCResources.cc
+++ b/LCS/WinCCWrapper/src/WinCCResources.cc
@@ -31,11 +31,62 @@ WinCCResources::WinCCResources(const std::string &project_name)
     init(project_name);
 }
 
-void WinCCResources::init(const std::string & /*project_name*/)
+WinCCResources::WinCCResources(const::std::string &program_name, const std::string &project_name, const int num)
 {
-    // TODO set specific project instead of current project.
-    char* ownArgv[] = {(char *)"WinCCWrapper", (char *)"-currentproj", (char *)"-log", (char *)"+stderr"};
-    int ownArgc = sizeof ownArgv / sizeof ownArgv[0];
+    init(program_name, project_name, num);
+}
+
+
+void WinCCResources::init(const::std::string &program_name, const std::string & project_name, const int num)
+{
+    std::vector<std::string> args{program_name};
+
+    if(project_name.compare("-currentproj") == 0){
+        args.push_back("-currentproj");
+    }else{
+        args.push_back("-proj");
+        args.push_back(project_name);
+    }
+    args.push_back("-log");
+    args.push_back("+stderr");
+
+    args.push_back("-num");
+    args.push_back(std::to_string(num));
+
+
+    int ownArgc = args.size();
+
+    char * ownArgv[ownArgc];
+
+    for(int i=0; i<ownArgc; i++){
+        ownArgv[i] = const_cast<char *>(args.at(i).c_str());
+    }
+
+    Resources::init(ownArgc, ownArgv);
+}
+
+
+
+void WinCCResources::init(const std::string & project_name)
+{
+    std::vector<std::string> args{"WinCCWrapper"};
+
+    if(project_name.compare("-currentproj") == 0){
+        args.push_back("-currentproj");
+    }else{
+        args.push_back("-proj");
+        args.push_back(project_name);
+    }
+    args.push_back("-log");
+    args.push_back("+stderr");
+
+    int ownArgc = args.size();
+
+    char * ownArgv[ownArgc];
+
+    for(int i=0; i<ownArgc; i++){
+        ownArgv[i] = const_cast<char *>(args.at(i).c_str());
+    }
 
     Resources::init(ownArgc, ownArgv);
 }
diff --git a/LCS/WinCCWrapper/src/WinCCWrapper.cc b/LCS/WinCCWrapper/src/WinCCWrapper.cc
index ab6191dc8d62d0f793b0c91541d59e3e2ecd4986..d8e129f59b8b81ac596a8ae80b6e7c423bd58c0f 100644
--- a/LCS/WinCCWrapper/src/WinCCWrapper.cc
+++ b/LCS/WinCCWrapper/src/WinCCWrapper.cc
@@ -43,6 +43,9 @@ using namespace std;
 
 //! Each datapoint has a human readable name in the wincc database, but the actual value is stored in a sub-item. Append that to each set/get datapoint name.
 static const string DP_SUFFIX = ":_original.._value";
+//! This property refers to the last set time
+static const string DP_SUFFIX_STIME = ":_original.._stime";
+
 
 WinCCWrapper::WinCCWrapper(const std::string &project_name) :
   resources(project_name)
@@ -50,6 +53,12 @@ WinCCWrapper::WinCCWrapper(const std::string &project_name) :
     manager = new WinCCManager();
 }
 
+WinCCWrapper::WinCCWrapper(const std::string &program_name, const std::string &project_name, const int num) :
+  resources(program_name, project_name, num)
+{
+    manager = new WinCCManager();
+}
+
 void WinCCWrapper::run()
 {
     manager->run();
@@ -65,11 +74,31 @@ void WinCCWrapper::connect_datapoints(const std::vector<std::string> &data_point
     manager->connect_datapoints(data_points);
 }
 
+void WinCCWrapper::connect_datapoints_multi(const std::vector<std::string> &data_points)
+{
+    manager->connect_datapoints_multiple(data_points);
+}
+
+void WinCCWrapper::disconnect_datapoints(const std::vector<std::string> &data_points)
+{
+    manager->connect_datapoints(data_points);
+}
+
+
+void WinCCWrapper::wait_for_event(long sec, long microSec){
+    manager->wait_for_event(sec, microSec);
+}
+
 void WinCCWrapper::set_connect_datapoints_callback(std::function<void(std::string name, std::string value)> callback)
 {
     manager->set_connect_datapoints_callback(callback);
 }
 
+void WinCCWrapper::set_connect_datapoints_callback(std::function<void(std::map<std::string, std::string>)> callback)
+{
+    manager->set_connect_datapoints_callback(callback);
+}
+
 // set_datapoint
 bool WinCCWrapper::set_datapoint(const std::string &name, int value, bool valid)
 {
@@ -99,7 +128,7 @@ bool WinCCWrapper::set_datapoint(const std::string &name, boost::python::tuple &
 bool WinCCWrapper::set_datapoint(const std::string &name, std::vector<int> &value, bool valid)
 {
     DynVar variable(VariableType::INTEGER_VAR);
-    
+
     for(auto iter = value.cbegin(); iter != value.cend(); iter++) {
         IntegerVar elem{*iter};
         variable.append(elem);}
@@ -142,6 +171,12 @@ bool WinCCWrapper::set_datapoint_time(const std::string &name, time_t value, boo
     return manager->set_datapoint(name + DP_SUFFIX, variable, valid);
 }
 
+boost::any WinCCWrapper::get_datapoint_any (const std::string &name){
+    boost::any datapoint_value;
+    manager->get_datapoint_any(name + DP_SUFFIX, datapoint_value);
+    return datapoint_value;
+}
+
 // get_datapoint
 template <typename T>
 bool WinCCWrapper::get_datapoint(const std::string &name, T &value)
@@ -213,6 +248,21 @@ time_t WinCCWrapper::get_datapoint_time(const std::string &name)
     throw std::runtime_error("Could not get datapoint");
 }
 
+std::string WinCCWrapper::get_formatted_datapoint(const std::string &name){
+    std::string value;
+    if(manager->get_datapoint(name, value)){
+        return value;
+    }
+    throw std::runtime_error("Could not get datapoint");
+}
+
+time_t WinCCWrapper::get_datapoint_set_time(const std::string &name){
+    struct tm value;
+    if(manager->get_datapoint(name + DP_SUFFIX_STIME, value))
+        return mktime(&value);
+    throw std::runtime_error("Could not get datapoint");
+}
+
 bool WinCCWrapper::set_datapoint_valid(const std::string &name)
 {
     return manager->set_datapoint_valid(name + DP_SUFFIX);
@@ -223,5 +273,8 @@ bool WinCCWrapper::set_datapoint_invalid(const std::string &name)
     return manager->set_datapoint_invalid(name + DP_SUFFIX);
 }
 
+bool WinCCWrapper::set_datapoint_any(const std::string &name, boost::any value){
+    return manager->set_datapoint_any(name + DP_SUFFIX, value);
+}
     } // namespace WINCCWRAPPER
 } // namespace LOFAR
diff --git a/LCS/WinCCWrapper/src/exceptions.h b/LCS/WinCCWrapper/src/exceptions.h
new file mode 100644
index 0000000000000000000000000000000000000000..cf0da769433fabc453caea25a37d76f885ff211f
--- /dev/null
+++ b/LCS/WinCCWrapper/src/exceptions.h
@@ -0,0 +1,12 @@
+class DatapointNameNotFound : public std::exception
+{
+private:
+    std::string message;
+public:
+    DatapointNameNotFound(const std::string & datapointName):
+        message{"Datapoint " + datapointName + " not found"}{}
+	const char * what () const throw ()
+    {
+    	return message.c_str();
+    }
+}
diff --git a/LCS/WinCCWrapper/test/CMakeLists.txt b/LCS/WinCCWrapper/test/CMakeLists.txt
index 93e3e67b7f1dd434c11c41fd399d18972c55937f..08c5036d1acb50498adbf4f295eefeb1bc8b999c 100644
--- a/LCS/WinCCWrapper/test/CMakeLists.txt
+++ b/LCS/WinCCWrapper/test/CMakeLists.txt
@@ -8,6 +8,15 @@ IF(BUILD_TESTING)
 
         lofar_add_bin_program(WinCCSet WinCCSet.cc)
         lofar_add_bin_program(WinCCGet WinCCGet.cc)
+        lofar_add_bin_program(WinCCQuery WinCCQuery.cc)
+        find_package(Boost COMPONENTS program_options system REQUIRED)
+
+        target_link_libraries(WinCCQuery
+            wincc_wrapper
+            ${Boost_LIBRARIES}
+
+        )
+
     ENDIF(WINCC_FOUND)
 ENDIF(BUILD_TESTING)
 
diff --git a/LCS/WinCCWrapper/test/WinCCGet.cc b/LCS/WinCCWrapper/test/WinCCGet.cc
index 5958d82e915ae681f7e11d206b062c0eebeb1983..aa10b76c422d4866cbec3a7e3bfa14e29dc745ae 100644
--- a/LCS/WinCCWrapper/test/WinCCGet.cc
+++ b/LCS/WinCCWrapper/test/WinCCGet.cc
@@ -3,28 +3,28 @@
 #include <WinCCWrapper.h>
 #include <vector>
 #include <iostream>
+#include <Resources.hxx>
 
 using namespace LOFAR::WINCCWRAPPER;
 using namespace std;
 
 void get_help(){
     cout << "Usage:" << endl;
-    cout << "WinCCGet \"datapoint_name\" datapoint_type" << endl;
+    cout << "WinCCGet \"datapoint_name\" datapoint_type project_name" << endl;
     cout << "Accepted datapoint types:" << endl;
     cout << "  int, float, string, list (for int lists)" << endl;
 }
 
 int main(int argc, char * argv[])
 {
-  bool asking_for_help = ((argc == 2) && (string(argv[1]) == "--help" || string(argv[1]) == "--h"));
-  bool invalid_args = (argc != 3);
+  bool asking_for_help = ((argc < 4) && (string(argv[1]) == "--help" || string(argv[1]) == "--h"));
+  bool invalid_args = (argc != 4);
 
   if (asking_for_help || invalid_args){
     get_help();
     return 0;
   }
-
-  WinCCWrapper wrapper{""};
+  WinCCWrapper wrapper{std::string(argv[3])};
   string dpname{argv[1]};
 
   if (string(argv[2]) == "int") {
diff --git a/LCS/WinCCWrapper/test/WinCCQuery.cc b/LCS/WinCCWrapper/test/WinCCQuery.cc
new file mode 100644
index 0000000000000000000000000000000000000000..108c626d304c56e1cb22ecbd3075328732488cee
--- /dev/null
+++ b/LCS/WinCCWrapper/test/WinCCQuery.cc
@@ -0,0 +1,68 @@
+
+
+
+#include <cstdlib>
+#include <string>
+#include <WinCCManager.h>
+#include <WinCCResources.h>
+
+#include <vector>
+#include <iostream>
+#include <Resources.hxx>
+
+#include <boost/program_options.hpp>
+#include <boost/any.hpp>
+
+
+
+using namespace LOFAR::WINCCWRAPPER;
+using namespace std;
+namespace po = boost::program_options;
+
+void set_options(po::options_description & description){
+    description.add_options()
+    ("help", "produce help message")
+    ("sql", po::value<std::string>(), "SQL_query")
+    ("project", po::value<std::string>(), "WinCC project");
+
+}
+
+int main(int argc, char * argv[])
+{
+    // Declare the supported options.
+    po::options_description desc("Query the WinCCDatabase");
+    set_options(desc);
+
+    po::variables_map vm;
+    po::store(po::parse_command_line(argc, argv, desc), vm);
+    po::notify(vm);
+
+
+    if (vm.count("help")) {
+        cout << desc << "\n";
+        return 1;
+    }
+
+    if (vm.count("sql") == 1 && vm.count("project") == 1) {
+
+        const string sql{vm["sql"].as<string>()};
+
+        WinCCResources resource{"WinCCQuery", vm["project"].as<string>(), 0};
+        WinCCManager manager;
+        cout << "The SQL is: [" << sql << "].\n";
+
+        std::vector<std::vector<std::string>> queryResult;
+        manager.get_query(sql, queryResult);
+        std::cout<< "RESULTS ----"<<"\n\n";
+        std::cout<< "datapoint" << "\t";
+        for(auto & row : queryResult){
+            for(std::string & column : row){
+                std::cout<<column<<"\t";
+            }
+            std::cout<<"\n";
+        }
+
+    } else {
+        cout << desc;
+    }
+}