diff --git a/bin/update_submodules.sh b/bin/update_submodules.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9dcb9745849c01bbf61b9ffae92c5c7cc21a5a8f
--- /dev/null
+++ b/bin/update_submodules.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+git submodule update --init
diff --git a/bootstrap/etc/lofar20rc.sh b/bootstrap/etc/lofar20rc.sh
index e3bc4ac1e71c43a92a5b7f2ee8f05339b92edeaf..9a9dd658b56f5d30bb1ff8c5de692bd8fe2164de 100755
--- a/bootstrap/etc/lofar20rc.sh
+++ b/bootstrap/etc/lofar20rc.sh
@@ -12,6 +12,10 @@
 ABSOLUTE_PATH=$(realpath $(dirname ${BASH_SOURCE}))
 export LOFAR20_DIR=${1:-$(realpath ${ABSOLUTE_PATH}/../..)}
 
+if [ ! -f "${LOFAR20_DIR}/.git/hooks/post-checkout" ]; then
+  alias git="cp ${LOFAR20_DIR}/bin/update_submodules.sh ${LOFAR20_DIR}/.git/hooks/post-checkout; cp ${LOFAR20_DIR}/bin/update_submodules.sh ${LOFAR20_DIR}/.git/hooks/post-merge; unalias git; git"
+fi
+
 # This needs to be modified for a development environment.
 # In case you run multiple Docker networks on the same host in parallel, you need to specify a unique
 # network name for each of them.
diff --git a/devices/devices/docker_device.py b/devices/devices/docker_device.py
index 5ff0ec366c436a2dfc75d4cd479219a04c6938d3..81abc26ee8ba4021b8e52bcefcf420a20cbdf28a 100644
--- a/devices/devices/docker_device.py
+++ b/devices/devices/docker_device.py
@@ -37,19 +37,6 @@ __all__ = ["Docker", "main"]
 
 @device_logging_to_python()
 class Docker(hardware_device):
-    """
-
-    **Properties:**
-
-    - Device Property
-        OPC_Server_Name
-            - Type:'DevString'
-        OPC_Server_Port
-            - Type:'DevULong'
-        OPC_Time_Out
-            - Type:'DevDouble'
-    """
-
     # -----------------
     # Device Properties
     # -----------------
@@ -103,19 +90,6 @@ class Docker(hardware_device):
     tango_rest_R = attribute_wrapper(comms_annotation={"container": "tango-rest"}, datatype=numpy.bool_)
     tango_rest_RW = attribute_wrapper(comms_annotation={"container": "tango-rest"}, datatype=numpy.bool_, access=AttrWriteType.READ_WRITE)
 
-    @log_exceptions()
-    def delete_device(self):
-        """Hook to delete resources allocated in init_device.
-
-        This method allows for any memory or other resources allocated in the
-        init_device method to be released.  This method is called by the device
-        destructor and by the device Init command (a Tango built-in).
-        """
-        self.debug_stream("Shutting down...")
-
-        self.Off()
-        self.debug_stream("Shut down.  Good bye.")
-
     # --------
     # overloaded functions
     # --------
@@ -124,9 +98,9 @@ class Docker(hardware_device):
         """ user code here. is called when the state is set to OFF """
         # Stop keep-alive
         try:
-            self.opcua_connection.stop()
+            self.docker_client.stop()
         except Exception as e:
-            self.warn_stream("Exception while stopping OPC ua connection in configure_for_off function: {}. Exception ignored".format(e))
+            self.warn_stream("Exception while stopping docker client in configure_for_off function: {}. Exception ignored".format(e))
 
     @log_exceptions()
     def configure_for_initialise(self):
@@ -135,14 +109,9 @@ class Docker(hardware_device):
         # set up the Docker client
         self.docker_client = DockerClient(self.Docker_Base_URL, self.Fault, self)
 
-        # map an access helper class
+        # tie attributes to client
         for i in self.attr_list():
-            try:
-                i.set_comm_client(self.docker_client)
-            except Exception as e:
-                # use the pass function instead of setting read/write fails
-                i.set_pass_func()
-                self.warn_stream("error while setting the attribute {} read/write function. {}".format(i, e))
+            i.set_comm_client(self.docker_client)
 
         self.docker_client.start()
 
diff --git a/devices/devices/hardware_device.py b/devices/devices/hardware_device.py
index 5192a304244dc169fc1e2990684061ee95928d00..a3abdb400466c9f601b0b85b7532ad2fb34f2aed 100644
--- a/devices/devices/hardware_device.py
+++ b/devices/devices/hardware_device.py
@@ -59,6 +59,9 @@ class hardware_device(Device, metaclass=AbstractDeviceMetas):
         The user triggers their transitions by the commands reflecting the target state (Initialise(), On(), Fault()).
     """
 
+    # list of property names too be set first by set_defaults
+    first_default_settings = []
+
     @classmethod
     def attr_list(cls):
         """ Return a list of all the attribute_wrapper members of this class. """
@@ -69,6 +72,7 @@ class hardware_device(Device, metaclass=AbstractDeviceMetas):
 
         self.value_dict = {i: i.initial_value() for i in self.attr_list()}
 
+    @log_exceptions()
     def init_device(self):
         """ Instantiates the device in the OFF state. """
 
@@ -77,6 +81,19 @@ class hardware_device(Device, metaclass=AbstractDeviceMetas):
 
         self.set_state(DevState.OFF)
 
+    @log_exceptions()
+    def delete_device(self):
+        """Hook to delete resources allocated in init_device.
+
+        This method allows for any memory or other resources allocated in the
+        init_device method to be released.  This method is called by the device
+        destructor and by the device Init command (a Tango built-in).
+        """
+        logger.info("Shutting down...")
+
+        self.Off()
+        logger.info("Shut down.  Good bye.")
+
     # --------
     # Commands
     # --------
@@ -183,18 +200,6 @@ class hardware_device(Device, metaclass=AbstractDeviceMetas):
         """Method always executed before any TANGO command is executed."""
         pass
 
-    def delete_device(self):
-        """Hook to delete resources allocated in init_device.
-
-        This method allows for any memory or other resources allocated in the
-        init_device method to be released.  This method is called by the device
-        destructor and by the device Init command (a Tango built-in).
-        """
-        self.debug_stream("Shutting down...")
-
-        self.Off()
-        self.debug_stream("Shut down.  Good bye.")
-
     @command()
     @only_in_states([DevState.STANDBY, DevState.ON])
     @DebugIt()
@@ -204,6 +209,11 @@ class hardware_device(Device, metaclass=AbstractDeviceMetas):
 
             A hardware point XXX is set to the value of the object member named XXX_default, if it exists.
             XXX_default can be f.e. a constant, or a device_property.
+
+            The points are set in the following order:
+                1) The python class property 'first_default_settings' is read, as an array of strings denoting property names. Each property
+                   is set in that order.
+                2) Any remaining default properties are set.
         """
 
         # we cannot write directly to our attribute, as that would not
@@ -212,20 +222,27 @@ class hardware_device(Device, metaclass=AbstractDeviceMetas):
         # obtain a proxy to myself, to write values
         proxy = DeviceProxy(self.get_name())
 
-        # for all my members
-        for name in dir(self):
-            attr = getattr(self, name)
-            # check if it's an attribute, and there is a default value available
-            if isinstance(attr, Attribute) and hasattr(self, f"{name}_default"):
-                try:
-                    default_value = getattr(self, f"{name}_default")
-
-                    # set the attribute to the configured default
-                    self.debug_stream(f"Setting attribute {name} to {default_value}")
-                    proxy.write_attribute(name, default_value)
-                except Exception as e:
-                    # log which attribute we're addressing
-                    raise Exception(f"Cannot assign default to attribute {name}") from e
+        # collect all attributes for which defaults are provided
+        attributes_with_defaults = [name for name in dir(self)
+                                    # collect all attribute members
+                                    if isinstance(getattr(self, name), Attribute)
+                                    # with a default set
+                                    and hasattr(self, f"{name}_default")]
+
+        # determine the order: first do the ones mentioned in default_settings_order
+        attributes_to_set = self.first_default_settings + [name for name in attributes_with_defaults if name not in self.first_default_settings]
+
+        # set them all
+        for name in attributes_to_set:
+            try:
+                default_value = getattr(self, f"{name}_default")
+
+                # set the attribute to the configured default
+                self.debug_stream(f"Setting attribute {name} to {default_value}")
+                proxy.write_attribute(name, default_value)
+            except Exception as e:
+                # log which attribute we're addressing
+                raise Exception(f"Cannot assign default to attribute {name}") from e
 
     @only_in_states([DevState.STANDBY, DevState.INIT, DevState.ON])
     @fault_on_error()
diff --git a/devices/devices/opcua_device.py b/devices/devices/opcua_device.py
new file mode 100644
index 0000000000000000000000000000000000000000..d95a8426ed0dc260c0f6eb6d85149e3f5f0ec4ba
--- /dev/null
+++ b/devices/devices/opcua_device.py
@@ -0,0 +1,115 @@
+# -*- coding: utf-8 -*-
+#
+# This file represents a top-level device
+#
+#
+#
+# Distributed under the terms of the APACHE license.
+# See LICENSE.txt for more info.
+
+""" Generic OPC-UA Device Server for LOFAR2.0
+
+"""
+
+# TODO(Corne): Remove sys.path.append hack once packaging is in place!
+import os, sys
+currentdir = os.path.dirname(os.path.realpath(__file__))
+parentdir = os.path.dirname(currentdir)
+sys.path.append(parentdir)
+
+# PyTango imports
+from tango import DebugIt
+from tango.server import device_property, attribute
+from tango import AttrWriteType
+import numpy
+# Additional import
+
+from devices.device_decorators import *
+
+from clients.opcua_client import OPCUAConnection
+from devices.hardware_device import hardware_device
+from common.lofar_logging import device_logging_to_python, log_exceptions
+from common.lofar_git import get_version
+
+__all__ = ["opcua_device", "main"]
+
+class opcua_device(hardware_device):
+    """
+
+    **Properties:**
+
+    - Device Property
+        OPC_Server_Name
+            - Type:'DevString'
+        OPC_Server_Port
+            - Type:'DevULong'
+        OPC_Time_Out
+            - Type:'DevDouble'
+    """
+
+    # -----------------
+    # Device Properties
+    # -----------------
+
+    OPC_Server_Name = device_property(
+        dtype='DevString',
+        mandatory=True
+    )
+
+    OPC_Server_Port = device_property(
+        dtype='DevULong',
+        mandatory=True
+    )
+
+    OPC_Time_Out = device_property(
+        dtype='DevDouble',
+        mandatory=True
+    )
+
+    OPC_namespace = device_property(
+        dtype='DevString',
+        mandatory=False,
+        default_value="http://lofar.eu"
+    )
+
+    # ----------
+    # Attributes
+    # ----------
+
+    opcua_missing_attributes_R = attribute(max_dim_x=128, dtype=(str,), fget=lambda self: numpy.array(self.opcua_missing_attributes, dtype=str), doc="OPC-UA attributes that this device requested, but which are not exposed on the server. These attributes are replaced with a no-op and thus do not function as expected.")
+
+    # --------
+    # overloaded functions
+    # --------
+
+    @log_exceptions()
+    def configure_for_initialise(self):
+        """ user code here. is called when the state is set to INIT """
+
+        # set up the OPC ua client
+        self.opcua_connection = OPCUAConnection("opc.tcp://{}:{}/".format(self.OPC_Server_Name, self.OPC_Server_Port), self.OPC_namespace, self.OPC_Time_Out, self.Fault, self)
+        self.opcua_missing_attributes = []
+
+        # map an access helper class
+        for i in self.attr_list():
+            try:
+                if not i.comms_id or i.comms_id == OPCUAConnection:
+                    i.set_comm_client(self.opcua_connection)
+            except Exception as e:
+                # use the pass function instead of setting read/write fails
+                i.set_pass_func()
+                self.opcua_missing_attributes.append(",".join(i.comms_annotation))
+
+                self.warn_stream("error while setting the attribute {} read/write function. {}".format(i, e))
+
+        self.opcua_connection.start()
+
+    @log_exceptions()
+    def configure_for_off(self):
+        """ user code here. is called when the state is set to OFF """
+        try:
+            # disconnect
+            self.opcua_connection.stop()
+        except Exception as e:
+            self.warn_stream("Exception while stopping OPC ua connection in configure_for_off function: {}. Exception ignored".format(e))
+
diff --git a/devices/devices/recv.py b/devices/devices/recv.py
index 26139c8473f28764286056aa5d7d1b0229fc9a68..7db40acc5c7dc4f04b8df1fb02185cf9eefcfb02 100644
--- a/devices/devices/recv.py
+++ b/devices/devices/recv.py
@@ -27,51 +27,36 @@ import numpy
 
 from device_decorators import *
 
-from clients.opcua_client import OPCUAConnection
 from clients.attribute_wrapper import attribute_wrapper
-from devices.hardware_device import hardware_device
+from devices.opcua_device import opcua_device
 from common.lofar_logging import device_logging_to_python, log_exceptions
 from common.lofar_git import get_version
 
 __all__ = ["RECV", "main"]
 
 @device_logging_to_python()
-class RECV(hardware_device):
-    """
-
-    **Properties:**
-
-    - Device Property
-        OPC_Server_Name
-            - Type:'DevString'
-        OPC_Server_Port
-            - Type:'DevULong'
-        OPC_Time_Out
-            - Type:'DevDouble'
-    """
-
+class RECV(opcua_device):
     # -----------------
     # Device Properties
     # -----------------
 
-    OPC_Server_Name = device_property(
-        dtype='DevString',
-        mandatory=True
+    Ant_mask_RW_default = device_property(
+        dtype='DevVarBooleanArray',
+        mandatory=False,
+        default_value=[[True] * 3] * 32
     )
 
-    OPC_Server_Port = device_property(
-        dtype='DevULong',
-        mandatory=True
+    RCU_mask_RW_default = device_property(
+        dtype='DevVarBooleanArray',
+        mandatory=False,
+        default_value=[True] * 32
     )
 
-    OPC_Time_Out = device_property(
-        dtype='DevDouble',
-        mandatory=True
-    )
-    OPC_namespace = device_property(
-        dtype='DevString',
-        mandatory=False
-    )
+    first_default_settings = [
+        # set the masks first, as those filter any subsequent settings
+        'Ant_mask_RW',
+        'RCU_mask_RW'
+    ]
 
     # ----------
     # Attributes
@@ -112,50 +97,9 @@ class RECV(hardware_device):
     RCU_translator_busy_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_translator_busy_R"], datatype=numpy.bool_)
     RCU_version_R = attribute_wrapper(comms_annotation=["2:PCC", "2:RCU_version_R"], datatype=numpy.str, dims=(32,))
 
-    @log_exceptions()
-    def delete_device(self):
-        """Hook to delete resources allocated in init_device.
-
-        This method allows for any memory or other resources allocated in the
-        init_device method to be released.  This method is called by the device
-        destructor and by the device Init command (a Tango built-in).
-        """
-        self.debug_stream("Shutting down...")
-
-        self.Off()
-        self.debug_stream("Shut down.  Good bye.")
-
     # --------
     # overloaded functions
     # --------
-    @log_exceptions()
-    def configure_for_off(self):
-        """ user code here. is called when the state is set to OFF """
-        # Stop keep-alive
-        try:
-            self.opcua_connection.stop()
-        except Exception as e:
-            self.warn_stream("Exception while stopping OPC ua connection in configure_for_off function: {}. Exception ignored".format(e))
-
-    @log_exceptions()
-    def configure_for_initialise(self):
-        """ user code here. is called when the state is set to INIT """
-
-        # set up the OPC ua client
-        self.OPCua_client = OPCUAConnection("opc.tcp://{}:{}/".format(self.OPC_Server_Name, self.OPC_Server_Port), "http://lofar.eu", self.OPC_Time_Out, self.Fault, self)
-
-        # map an access helper class
-        for i in self.attr_list():
-            try:
-                i.set_comm_client(self.OPCua_client)
-            except Exception as e:
-                # use the pass function instead of setting read/write fails
-                i.set_pass_func()
-                self.warn_stream("error while setting the RECV attribute {} read/write function. {}".format(i, e))
-
-        self.OPCua_client.start()
-
-
 
     # --------
     # Commands
@@ -168,7 +112,7 @@ class RECV(hardware_device):
 
         :return:None
         """
-        self.OPCua_client.call_method(["2:PCC","2:RCU_off"])
+        self.opcua_connection.call_method(["2:PCC","2:RCU_off"])
 
     @command()
     @DebugIt()
@@ -178,7 +122,7 @@ class RECV(hardware_device):
 
         :return:None
         """
-        self.OPCua_client.call_method(["2:PCC","2:RCU_on"])
+        self.opcua_connection.call_method(["2:PCC","2:RCU_on"])
 
     @command()
     @DebugIt()
@@ -188,7 +132,7 @@ class RECV(hardware_device):
 
         :return:None
         """
-        self.OPCua_client.call_method(["2:PCC","2:ADC_on"])
+        self.opcua_connection.call_method(["2:PCC","2:ADC_on"])
 
     @command()
     @DebugIt()
@@ -198,7 +142,7 @@ class RECV(hardware_device):
 
         :return:None
         """
-        self.OPCua_client.call_method(["2:PCC","2:RCU_update"])
+        self.opcua_connection.call_method(["2:PCC","2:RCU_update"])
 
     @command()
     @DebugIt()
@@ -208,7 +152,7 @@ class RECV(hardware_device):
 
         :return:None
         """
-        self.OPCua_client.call_method(["2:PCC","2:CLK_off"])
+        self.opcua_connection.call_method(["2:PCC","2:CLK_off"])
 
     @command()
     @DebugIt()
@@ -218,7 +162,7 @@ class RECV(hardware_device):
 
         :return:None
         """
-        self.OPCua_client.call_method(["2:PCC","2:CLK_on"])
+        self.opcua_connection.call_method(["2:PCC","2:CLK_on"])
 
     @command()
     @DebugIt()
@@ -228,7 +172,7 @@ class RECV(hardware_device):
 
         :return:None
         """
-        self.OPCua_client.call_method(["2:PCC","2:CLK_PLL_setup"])
+        self.opcua_connection.call_method(["2:PCC","2:CLK_PLL_setup"])
 
     def _initialise_hardware(self):
         """ Initialise the RCU hardware. """
diff --git a/devices/devices/sdp/sdp.py b/devices/devices/sdp/sdp.py
index 16f6d89737742f1f3d475c619a60513e4579a115..221afb245361d4f330aab42b395532624fb4edde 100644
--- a/devices/devices/sdp/sdp.py
+++ b/devices/devices/sdp/sdp.py
@@ -24,9 +24,8 @@ from tango.server import device_property, attribute
 from tango import AttrWriteType
 # Additional import
 
-from clients.opcua_client import OPCUAConnection
 from clients.attribute_wrapper import attribute_wrapper
-from devices.hardware_device import hardware_device
+from devices.opcua_device import opcua_device
 
 from common.lofar_logging import device_logging_to_python, log_exceptions
 from common.lofar_git import get_version
@@ -36,37 +35,15 @@ import numpy
 __all__ = ["SDP", "main"]
 
 @device_logging_to_python()
-class SDP(hardware_device):
-    """
-
-    **Properties:**
-
-    - Device Property
-        OPC_Server_Name
-            - Type:'DevString'
-        OPC_Server_Port
-            - Type:'DevULong'
-        OPC_Time_Out
-            - Type:'DevDouble'
-    """
-
+class SDP(opcua_device):
     # -----------------
     # Device Properties
     # -----------------
 
-    OPC_Server_Name = device_property(
-        dtype='DevString',
-        mandatory=True
-    )
-
-    OPC_Server_Port = device_property(
-        dtype='DevULong',
-        mandatory=True
-    )
-
-    OPC_Time_Out = device_property(
-        dtype='DevDouble',
-        mandatory=True
+    TR_fpga_mask_RW_default = device_property(
+        dtype='DevVarBooleanArray',
+        mandatory=False,
+        default_value=[True] * 16
     )
 
     FPGA_processing_enable_RW_default = device_property(
@@ -92,6 +69,11 @@ class SDP(hardware_device):
         default_value=[[8192] * 12 * 512] * 16
     )
 
+    first_default_settings = [
+        # set the masks first, as those filter any subsequent settings
+        'TR_fpga_mask_RW'
+    ]
+
     # ----------
     # Attributes
     # ----------
@@ -151,55 +133,9 @@ class SDP(hardware_device):
     TR_tod_R = attribute_wrapper(comms_annotation=["2:TR_tod_R"], datatype=numpy.int64, dims=(2,))
     TR_tod_pps_delta_R = attribute_wrapper(comms_annotation=["2:TR_tod_pps_delta_R"], datatype=numpy.double)
 
-    def always_executed_hook(self):
-        """Method always executed before any TANGO command is executed."""
-        pass
-
-    @log_exceptions()
-    def delete_device(self):
-        """Hook to delete resources allocated in init_device.
-
-        This method allows for any memory or other resources allocated in the
-        init_device method to be released.  This method is called by the device
-        destructor and by the device Init command (a Tango built-in).
-        """
-        self.debug_stream("Shutting down...")
-
-        self.Off()
-        self.debug_stream("Shut down.  Good bye.")
-
     # --------
     # overloaded functions
     # --------
-    @log_exceptions()
-    def configure_for_off(self):
-        """ user code here. is called when the state is set to OFF """
-
-        # Stop keep-alive
-        try:
-            self.OPCua_client.stop()
-        except Exception as e:
-            self.warn_stream("Exception while stopping OPC ua connection in configure_for_off function: {}. Exception ignored".format(e))
-
-    @log_exceptions()
-    def configure_for_initialise(self):
-        """ user code here. is called when the sate is set to INIT """
-        """Initialises the attributes and properties of the SDP."""
-
-        # set up the OPC ua client
-        self.OPCua_client = OPCUAConnection("opc.tcp://{}:{}/".format(self.OPC_Server_Name, self.OPC_Server_Port), "http://lofar.eu", self.OPC_Time_Out, self.Fault, self)
-
-        # map an access helper class
-        for i in self.attr_list():
-            try:
-                i.set_comm_client(self.OPCua_client)
-            except Exception as e:
-                # use the pass function instead of setting read/write fails
-                i.set_pass_func()
-                self.warn_stream("error while setting the SDP attribute {} read/write function. {}".format(i, e))
-                pass
-
-        self.OPCua_client.start()
 
     # --------
     # Commands
diff --git a/devices/devices/sdp/sst.py b/devices/devices/sdp/sst.py
index 3b2f36236a841adb0511b284cbeb4a0fbc6ee296..fe1b353b17737d56f5566da9cc7913e16ff828a6 100644
--- a/devices/devices/sdp/sst.py
+++ b/devices/devices/sdp/sst.py
@@ -57,12 +57,29 @@ class SST(Statistics):
         mandatory=True
     )
 
+    FPGA_sst_offload_enable_RW_default = device_property(
+        dtype='DevVarBooleanArray',
+        mandatory=False,
+        default_value=[True] * 16
+    )
+
     FPGA_sst_offload_weighted_subbands_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
         default_value=[True] * 16
     )
 
+    first_default_settings = [
+        'FPGA_sst_offload_hdr_eth_destination_mac_RW',
+        'FPGA_sst_offload_hdr_ip_destination_address_RW',
+        'FPGA_sst_offload_hdr_udp_destination_port_RW',
+
+        'FPGA_sst_offload_weighted_subbands_RW',
+
+        # enable only after the offloading is configured correctly
+        'FPGA_sst_offload_enable_RW'
+    ]
+
     # ----------
     # Attributes
     # ----------
diff --git a/devices/devices/sdp/statistics.py b/devices/devices/sdp/statistics.py
index 7d0b970b089ff29931bfc088f8b4b208d347402c..a884783ddd85c669e35a2230e72e3e4ca2f85d60 100644
--- a/devices/devices/sdp/statistics.py
+++ b/devices/devices/sdp/statistics.py
@@ -29,7 +29,7 @@ from clients.statistics_client import StatisticsClient
 from clients.opcua_client import OPCUAConnection
 from clients.attribute_wrapper import attribute_wrapper
 
-from devices.hardware_device import hardware_device
+from devices.opcua_device import opcua_device
 
 from common.lofar_git import get_version
 from common.lofar_logging import device_logging_to_python, log_exceptions
@@ -41,7 +41,7 @@ import numpy
 
 __all__ = ["Statistics"]
 
-class Statistics(hardware_device, metaclass=ABCMeta):
+class Statistics(opcua_device, metaclass=ABCMeta):
 
     # In derived classes, set this to a subclass of StatisticsCollector
     @property
@@ -53,21 +53,6 @@ class Statistics(hardware_device, metaclass=ABCMeta):
     # Device Properties
     # -----------------
 
-    OPC_Server_Name = device_property(
-        dtype='DevString',
-        mandatory=True
-    )
-
-    OPC_Server_Port = device_property(
-        dtype='DevULong',
-        mandatory=True
-    )
-
-    OPC_Time_Out = device_property(
-        dtype='DevDouble',
-        mandatory=True
-    )
-
     Statistics_Client_UDP_Port = device_property(
         dtype='DevUShort',
         mandatory=True
@@ -124,16 +109,15 @@ class Statistics(hardware_device, metaclass=ABCMeta):
         except Exception as e:
             logger.exception("Exception while stopping statistics_client in configure_for_off. Exception ignored")
 
-        try:
-            self.OPCUA_client.stop()
-        except Exception as e:
-            logger.exception("Exception while stopping OPC UA connection in configure_for_off. Exception ignored")
+        super().configure_for_off()
 
     @log_exceptions()
     def configure_for_initialise(self):
         """ user code here. is called when the sate is set to INIT """
         """Initialises the attributes and properties of the statistics device."""
 
+        super().configure_for_initialise()
+
         # Options for UDPReceiver
         udp_options = {
             "udp_port": self.Statistics_Client_UDP_Port,
@@ -148,27 +132,12 @@ class Statistics(hardware_device, metaclass=ABCMeta):
 
         self.statistics_collector = self.STATISTICS_COLLECTOR_CLASS()
         self.statistics_client = StatisticsClient(self.statistics_collector, udp_options, tcp_options, self.Fault, self)
-
-        self.OPCUA_client = OPCUAConnection("opc.tcp://{}:{}/".format(self.OPC_Server_Name, self.OPC_Server_Port), "http://lofar.eu", self.OPC_Time_Out, self.Fault, self)
-
-        # map an access helper class
-        for i in self.attr_list():
-            try:
-                if i.comms_id == StatisticsClient:
-                    i.set_comm_client(self.statistics_client)
-                elif i.comms_id == OPCUAConnection:
-                    i.set_comm_client(self.OPCUA_client)
-                else:
-                    raise ValueError("Cannot set comm client for attribute {}: Unknown comms_id {}".format(i, i.comms_id))
-            except Exception as e:
-                # use the pass function instead of setting read/write fails
-                i.set_pass_func()
-                self.warn_stream("error while setting the sst attribute {} read/write function. {}. using pass function instead".format(i, e))
-                pass
-
         self.statistics_client.start()
 
-        self.OPCUA_client.start()
+        # tie attributes to client
+        for i in self.attr_list():
+            if i.comms_id == StatisticsClient:
+                i.set_comm_client(self.statistics_client)
 
     # --------
     # Commands
diff --git a/devices/devices/sdp/xst.py b/devices/devices/sdp/xst.py
index caeeb5d3488369ecaf17208d1b33c2b7e6c76511..af3766738847fbee48cff17d11a5a8901ee169c2 100644
--- a/devices/devices/sdp/xst.py
+++ b/devices/devices/sdp/xst.py
@@ -75,6 +75,23 @@ class XST(Statistics):
         default_value=[[0,102,0,0,0,0,0,0]] * 16
     )
 
+    FPGA_xst_offload_enable_RW_default = device_property(
+        dtype='DevVarBooleanArray',
+        mandatory=False,
+        default_value=[True] * 16
+    )
+
+    first_default_settings = [
+        'FPGA_xst_offload_hdr_eth_destination_mac_RW',
+        'FPGA_xst_offload_hdr_ip_destination_address_RW',
+        'FPGA_xst_offload_hdr_udp_destination_port_RW',
+
+        'FPGA_xst_subband_select_RW',
+
+        # enable only after the offloading is configured correctly
+        'FPGA_xst_offload_enable_RW'
+    ]
+
     # ----------
     # Attributes
     # ----------
diff --git a/devices/devices/unb2.py b/devices/devices/unb2.py
index 7c2575991605354de5bba608906fb9ea248f021b..83fb44ca93cb38795cc77b49354aa53dfafc5cf8 100644
--- a/devices/devices/unb2.py
+++ b/devices/devices/unb2.py
@@ -23,9 +23,8 @@ from tango.server import device_property, attribute
 from tango import AttrWriteType
 # Additional import
 
-from clients.opcua_client import OPCUAConnection
 from clients.attribute_wrapper import attribute_wrapper
-from devices.hardware_device import hardware_device
+from devices.opcua_device import opcua_device
 
 from common.lofar_logging import device_logging_to_python, log_exceptions
 from common.lofar_git import get_version
@@ -35,39 +34,11 @@ import numpy
 __all__ = ["UNB2", "main"]
 
 @device_logging_to_python()
-class UNB2(hardware_device):
-    """
-
-    **Properties:**
-
-    - Device Property
-        OPC_Server_Name
-            - Type:'DevString'
-        OPC_Server_Port
-            - Type:'DevULong'
-        OPC_Time_Out
-            - Type:'DevDouble'
-    """
-
+class UNB2(opcua_device):
     # -----------------
     # Device Properties
     # -----------------
 
-    OPC_Server_Name = device_property(
-        dtype='DevString',
-        mandatory=True
-    )
-
-    OPC_Server_Port = device_property(
-        dtype='DevULong',
-        mandatory=True
-    )
-
-    OPC_Time_Out = device_property(
-        dtype='DevDouble',
-        mandatory=True
-    )
-
     # ----------
     # Attributes
     # ----------
@@ -167,49 +138,10 @@ class UNB2(hardware_device):
 
     # QualifiedName(2: UNB2_on)
     # QualifiedName(2: UNB2_off)
-    @log_exceptions()
-    def delete_device(self):
-        """Hook to delete resources allocated in init_device.
-
-        This method allows for any memory or other resources allocated in the
-        init_device method to be released.  This method is called by the device
-        destructor and by the device Init command (a Tango built-in).
-        """
-        self.debug_stream("Shutting down...")
-
-        self.Off()
-        self.debug_stream("Shut down.  Good bye.")
 
     # --------
     # overloaded functions
     # --------
-    @log_exceptions()
-    def configure_for_off(self):
-        """ user code here. is called when the state is set to OFF """
-        # Stop keep-alive
-        try:
-            self.opcua_connection.stop()
-        except Exception as e:
-            self.warn_stream("Exception while stopping OPC ua connection in configure_for_off function: {}. Exception ignored".format(e))
-
-    @log_exceptions()
-    def configure_for_initialise(self):
-        """ user code here. is called when the sate is set to INIT """
-        """Initialises the attributes and properties of theRECV."""
-
-        # set up the OPC ua client
-        self.OPCua_client = OPCUAConnection("opc.tcp://{}:{}/".format(self.OPC_Server_Name, self.OPC_Server_Port), "http://lofar.eu", self.OPC_Time_Out, self.Fault, self)
-
-        # map an access helper class
-        for i in self.attr_list():
-            try:
-                i.set_comm_client(self.OPCua_client)
-            except Exception as e:
-                # use the pass function instead of setting read/write fails
-                i.set_pass_func()
-                self.warn_stream("error while setting the UNB2 attribute {} read/write function. {}".format(i, e))
-
-        self.OPCua_client.start()
 
     # --------
     # Commands