diff --git a/include/D_textUnifier.h b/include/D_textUnifier.h
new file mode 100644
index 0000000000000000000000000000000000000000..4fff778cd963f8d3e52a4d96566ef45818424d94
--- /dev/null
+++ b/include/D_textUnifier.h
@@ -0,0 +1,21 @@
+#ifndef D_TEXTUNIFIER_H
+#define D_TEXTUNIFIER_H
+
+#include <d_fct.h>
+
+/** A compatibility class that adds the constructor which would create a history,
+ *  and the set_and_archive function to the D_text interface. As this does not
+ *  have history it just calls the non-history equivalent.
+ *  This class was introduces to avoid template specialisations in DoocsProcessScalar.
+ *  (Local specialisations of functions don't work because one would have to
+ */
+struct D_textUnifier: public D_text {
+
+    using D_text::D_text;
+    D_textUnifier(EqFct* eqFct, std::string doocsPropertyName);
+
+    void set_and_archive(const std::string &str);
+    D_hist * get_histPointer ();
+};
+
+#endif // D_TEXTUNIFIER_H
diff --git a/include/DoocsProcessScalar.h b/include/DoocsProcessScalar.h
index 9000e29f9b0c523d0276eb539f860d369e6de471..9780d565839468355ca7392c606cfde99a90e004 100644
--- a/include/DoocsProcessScalar.h
+++ b/include/DoocsProcessScalar.h
@@ -130,87 +130,6 @@ namespace ChimeraTK {
     bool _publishZMQ{false};
   };
 
-  /** Template specialisation for D_text, which has a different interface */
-  template<typename T>
-  class DoocsProcessScalar<T, D_text> : public D_text, public boost::noncopyable {
-   public:
-    void updateDoocsBuffer() {
-      // Note: we already own the location lock by specification of the
-      // DoocsUpdater
-      auto data = _processScalar->accessData(0);
-      this->set_value(data);
-      if(_publishZMQ) {
-        dmsg_info info;
-        memset(&info, 0, sizeof(info));
-        auto sinceEpoch = _processScalar->getVersionNumber().getTime().time_since_epoch();
-        auto time = std::chrono::duration_cast<std::chrono::microseconds>(sinceEpoch);
-        info.sec = time.count() / 1000000;
-        info.usec = time.count() % 1000000;
-        info.ident = _macroPulseNumberSource->accessData(0);
-        this->send(&info);
-      }
-    }
-
-    DoocsProcessScalar(EqFct* eqFct, std::string doocsPropertyName,
-        boost::shared_ptr<typename ChimeraTK::NDRegisterAccessor<T>> const& processScalar, DoocsUpdater& updater)
-    : D_text(doocsPropertyName.c_str(), eqFct), _processScalar(processScalar) {
-      if(processScalar->isReadable()) {
-        updater.addVariable(ChimeraTK::ScalarRegisterAccessor<T>(processScalar), eqFct,
-            std::bind(&DoocsProcessScalar<T, D_text>::updateDoocsBuffer, this));
-      }
-    }
-
-    DoocsProcessScalar(std::string doocsPropertyName, EqFct* eqFct,
-        boost::shared_ptr<typename ChimeraTK::NDRegisterAccessor<T>> const& processScalar, DoocsUpdater& updater)
-    : D_text(doocsPropertyName.c_str(), eqFct), _processScalar(processScalar) {
-      if(processScalar->isReadable()) {
-        updater.addVariable(ChimeraTK::ScalarRegisterAccessor<T>(processScalar), eqFct,
-            std::bind(&DoocsProcessScalar<T, D_text>::updateDoocsBuffer, this));
-      }
-    }
-
-    /**
-     * Override the Doocs set method which is triggered by the RPC calls.
-     */
-    void set(EqAdr* adr, EqData* data1, EqData* data2, EqFct* eqfct) override {
-      // only assign the value if the variable is writeable
-      // Otherwise the content displayed by Doocs and the value in the application
-      // are inconsistent
-      if(_processScalar->isWriteable()) {
-        D_text::set(adr, data1, data2, eqfct);
-        // let the DOOCS_T set function do all the dirty work and use the
-        // get_value function afterwards to get the already assigned value
-        _processScalar->accessData(0) = this->value();
-        _processScalar->write();
-      }
-    }
-
-    /**
-     * Override the Doocs auto_init() method, which is called after initialising
-     * the value of the property from the config file.
-     */
-    void auto_init(void) override {
-      D_text::auto_init();
-      // send the current value to the device
-      if(_processScalar->isWriteable()) {
-        _processScalar->accessData(0) = D_text::value();
-        _processScalar->write();
-      }
-    }
-
-    void publishZeroMQ() { _publishZMQ = true; }
-
-    void setMacroPulseNumberSource(boost::shared_ptr<ChimeraTK::NDRegisterAccessor<int64_t>> macroPulseNumberSource) {
-      _macroPulseNumberSource = macroPulseNumberSource;
-    }
-
-   protected:
-    boost::shared_ptr<ChimeraTK::NDRegisterAccessor<T>> _processScalar;
-    boost::shared_ptr<ChimeraTK::NDRegisterAccessor<int64_t>> _macroPulseNumberSource;
-    DataConsistencyGroup _consistencyGroup;
-    bool _publishZMQ{false};
-  };
-
 } // namespace ChimeraTK
 
 #endif // __DOOCS_PROCESS_SCALAR_H__
diff --git a/src/D_textUnifier.cpp b/src/D_textUnifier.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4eeb337be906d081d3a72101edc7aa194b716d0e
--- /dev/null
+++ b/src/D_textUnifier.cpp
@@ -0,0 +1,14 @@
+#include "D_textUnifier.h"
+
+// just call the constructor without history (the only one)
+D_textUnifier::D_textUnifier(EqFct* eqFct, std::string doocsPropertyName)
+    : D_text(doocsPropertyName, eqFct){
+}
+
+void D_textUnifier::set_and_archive(const std::string &str){
+    set_value(str);
+}
+
+D_hist * D_textUnifier::get_histPointer(){
+    return nullptr;
+}
diff --git a/src/DoocsPVFactory.cc b/src/DoocsPVFactory.cc
index 7b39bd555be21b200652ba0cbc4a7b3633581b15..cb109276e1da496cd356154e0ef2d78232c8cfb5 100644
--- a/src/DoocsPVFactory.cc
+++ b/src/DoocsPVFactory.cc
@@ -4,6 +4,7 @@
 #include "DoocsProcessScalar.h"
 #include "DoocsSpectrum.h"
 #include "DoocsXY.h"
+#include "D_textUnifier.h"
 #include <d_fct.h>
 
 #include "DoocsPVFactory.h"
@@ -88,7 +89,7 @@ namespace ChimeraTK {
   }
 
   template<>
-  boost::shared_ptr<D_fct> DoocsPVFactory::createDoocsScalar<std::string, D_text>(
+  boost::shared_ptr<D_fct> DoocsPVFactory::createDoocsScalar<std::string, D_textUnifier>(
       AutoPropertyDescription const& propertyDescription, DecoratorType /*decoratorType*/) {
     auto processVariable = _controlSystemPVManager->getProcessVariable(propertyDescription.source);
 
@@ -106,7 +107,7 @@ namespace ChimeraTK {
     assert(processArray->getNumberOfChannels() == 1);
     assert(processArray->getNumberOfSamples() == 1); // array of strings is not supported
     boost::shared_ptr<D_fct> doocsPV(
-        new DoocsProcessScalar<std::string, D_text>(_eqFct, propertyDescription.name.c_str(), processArray, _updater));
+        new DoocsProcessScalar<std::string, D_textUnifier>(_eqFct, propertyDescription.name.c_str(), processArray, _updater));
 
     // set read only mode if configures in the xml file or for output variables
     if(!processArray->isWriteable() || !propertyDescription.isWriteable) {
@@ -115,7 +116,7 @@ namespace ChimeraTK {
 
     // publish via ZeroMQ if configured in the xml file
     if(propertyDescription.publishZMQ) {
-      boost::dynamic_pointer_cast<DoocsProcessScalar<std::string, D_text>>(doocsPV)->publishZeroMQ();
+      boost::dynamic_pointer_cast<DoocsProcessScalar<std::string, D_textUnifier>>(doocsPV)->publishZeroMQ();
     }
 
     // set macro pulse number source, if configured
@@ -132,7 +133,7 @@ namespace ChimeraTK {
         throw ChimeraTK::logic_error("The property '" + mpnDecorated->getName() +
             "' is used as a macro pulse number source, but it is not readable.");
       }
-      boost::dynamic_pointer_cast<DoocsProcessScalar<std::string, D_text>>(doocsPV)->setMacroPulseNumberSource(
+      boost::dynamic_pointer_cast<DoocsProcessScalar<std::string, D_textUnifier>>(doocsPV)->setMacroPulseNumberSource(
           mpnDecorated);
       _updater.addVariable(ChimeraTK::ScalarRegisterAccessor<int64_t>(mpnDecorated), _eqFct, [] {});
     }
@@ -356,7 +357,7 @@ boost::shared_ptr<D_fct> DoocsPVFactory::autoCreate(std::shared_ptr<PropertyDesc
           valueType, *processVariable, *autoPropertyDescription, DecoratorType::C_style_conversion);
     case AutoPropertyDescription::DataType::Auto:
       if(valueType == typeid(std::string)) {
-        return typedCreateScalarOrArray<D_text, std::string, std::nullptr_t, std::nullptr_t>(
+        return typedCreateScalarOrArray<D_textUnifier, std::string, std::nullptr_t, std::nullptr_t>(
             valueType, *processVariable, *autoPropertyDescription, DecoratorType::range_checking);
       }
       throw std::logic_error("DoocsPVFactory does not implement a data type it should!");