diff --git a/tangostationcontrol/VERSION b/tangostationcontrol/VERSION
index ceab6e11ece0bcec917c12e11d350946f085d549..6da28dde76d6550e3d398a70a9a8231256774669 100644
--- a/tangostationcontrol/VERSION
+++ b/tangostationcontrol/VERSION
@@ -1 +1 @@
-0.1
\ No newline at end of file
+0.1.1
\ No newline at end of file
diff --git a/tangostationcontrol/tangostationcontrol/common/type_checking.py b/tangostationcontrol/tangostationcontrol/common/type_checking.py
index e896e708c757da78331e0aa5655f3c8e7a66bfda..f6686b54b86b94aa745ac311b9f71e622ec87ef8 100644
--- a/tangostationcontrol/tangostationcontrol/common/type_checking.py
+++ b/tangostationcontrol/tangostationcontrol/common/type_checking.py
@@ -9,15 +9,17 @@ import numpy
 
 
 def is_sequence(obj):
-    """Identify sequences / collections"""
+    """True for sequences, positionally ordered collections
+    See https://www.pythontutorial.net/advanced-python/python-sequences/
+    """
     return isinstance(obj, Sequence) or isinstance(obj, numpy.ndarray)
 
 
 def sequence_not_str(obj):
-    """Separate sequences / collections from str, byte or bytearray"""
+    """True for sequences that are not str, bytes or bytearray"""
     return is_sequence(obj) and not isinstance(obj, (str, bytes, bytearray))
 
 
 def type_not_sequence(obj):
-    """Separate sequences / collections from types"""
+    """True for types that are not sequences"""
     return not is_sequence(obj) and isinstance(obj, type)
diff --git a/tangostationcontrol/tangostationcontrol/devices/README.md b/tangostationcontrol/tangostationcontrol/devices/README.md
index d7c5a64a95fa9f43c7a2524a71cf1379e6527341..4b7923faf4804b6fc0e33ab78d4765f16860e253 100644
--- a/tangostationcontrol/tangostationcontrol/devices/README.md
+++ b/tangostationcontrol/tangostationcontrol/devices/README.md
@@ -18,3 +18,4 @@ If a new device is added, it will (likely) need to be referenced in several plac
 - Add to `tangostationcontrol/docs/source/devices/` to mention the device in the end-user documentation.
 - Adjust `tangostationcontrol/docs/source/index.rst` to include the newly created file in `docs/source/devices/`.
 - Adjust `docker-compose/tango-prometheus-exporter/lofar2-policy.json` to include this device in the prometheus exporter
+- Adjust `tangostationcontrol/tangostationcontrol/devices/docker_device.py` to have the device container available as R and RW attributes. 
diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/antennafield.py
index 93e1a8c67e4e9cad3babce6acfe2e17a0fd0dc13..e3289b9b7df79719cfdf56e3508a66bcaeb869db 100644
--- a/tangostationcontrol/tangostationcontrol/devices/antennafield.py
+++ b/tangostationcontrol/tangostationcontrol/devices/antennafield.py
@@ -16,7 +16,6 @@ from tango import DeviceProxy, DevSource, AttrWriteType, DevVarFloatArray, DevVa
 from tango.server import device_property, attribute, command
 
 # Additional import
-from tangostationcontrol.common.type_checking import sequence_not_str
 from tangostationcontrol.common.type_checking import type_not_sequence
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.devices.lofar_device import lofar_device
@@ -410,15 +409,15 @@ class AntennaField(lofar_device):
 
         """
 
+        # returns sparse multidimensional array, uncontrolled values set to None
         mapped_value = self.__mapper.map_write(mapped_point, value)
 
         for idx, recv_proxy in enumerate(self.recv_proxies):
             new_values = mapped_value[idx]
 
-            # TODO(Corne): Resolve potential lost update race condition
-            current_values = recv_proxy.read_attribute(mapped_point).value
-            self.__mapper.merge_write(new_values, current_values)
-            recv_proxy.write_attribute(mapped_point, new_values.astype(dtype=cast_type))
+            self.atomic_read_modify_write_attribute(
+                new_values, recv_proxy, mapped_point, cast_type=cast_type
+            )
     
     # --------
     # Overloaded functions
@@ -556,24 +555,6 @@ class AntennaToRecvMapper(object):
 
         return mapped_values
 
-    def merge_write(self, merge_values: List[any], current_values: List[any]):
-        """Merge values as retrieved from :py:func:`~map_write` with current_values
-
-        This method will modify the contents of merge_values.
-
-        To be used by the :py:class:`~AntennaField` device to remove None fields
-        from mapped_values with recently retrieved current_values from RECV device.
-
-        :param merge_values: values as retrieved from :py:func:`~map_write`
-        :param current_values: values retrieved from RECV device on specific attribute
-        """
-
-        for idx, value in enumerate(merge_values):
-            if sequence_not_str(value):
-                self.merge_write(merge_values[idx], current_values[idx])
-            elif value is None:
-                merge_values[idx] = current_values[idx]
-
     def _mapped_r_values(self, recv_results: List[any], default_values: List[any]):
         """Mapping for read using :py:attribute:`~_control_mapping` and shallow copy"""
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py
index 8d51d269f3e83eb2eb0a45442cec4209e00ecf13..42ce74d74c7efc6ca27d4b4ef8a53988441fd04a 100644
--- a/tangostationcontrol/tangostationcontrol/devices/boot.py
+++ b/tangostationcontrol/tangostationcontrol/devices/boot.py
@@ -18,6 +18,7 @@ from tango import DebugIt
 from tango.server import command
 from tango.server import device_property, attribute
 from tango import AttrWriteType, DeviceProxy, DevState, DevSource
+
 # Additional import
 import numpy
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/ccd.py b/tangostationcontrol/tangostationcontrol/devices/ccd.py
index e053d26c4e879fca236a4277742c96c0f119d350..b17184d29c2ffdbead1dc1a72e086c5d07b6dea3 100644
--- a/tangostationcontrol/tangostationcontrol/devices/ccd.py
+++ b/tangostationcontrol/tangostationcontrol/devices/ccd.py
@@ -118,7 +118,7 @@ class CCD(opcua_device):
     def reset_hardware(self):
         """ Initialise the CCD hardware. """
 
-        # Cycle clock
+        # Cycle clock. Quickly toggling the heater should not cool the heater down too much.
         self.CCD_off()
         self.wait_attribute("CCDTR_translator_busy_R", False, self.CCD_On_Off_timeout)
         self.CCD_on()
@@ -126,16 +126,20 @@ class CCD(opcua_device):
 
         if not self.read_attribute("CCD_PLL_locked_R"):
             if self.read_attribute("CCDTR_I2C_error_R"):
-                raise Exception("I2C is not working. Maybe power cycle subrack to restart CLK board and translator?")
+                raise Exception("I2C is not working.")
             else:
-                raise Exception("CCD clock is not locked")
+                logger.warning("CCD not locked, this may indicate the clock has not yet warmed up")
 
     def _disable_hardware(self):
-        """ Disable the CCD hardware. """
+        """ Disable the CCD hardware.
+        WARNING: The CCD contains a heater that takes about 15 minutes to fully heat up from a cold start.
+        This
+        """
 
         # Turn off the CCD
         self.CCD_off()
         self.wait_attribute("CCDTR_translator_busy_R", False, self.CCD_On_Off_timeout)
+        logger.debug("Put CCD in off state")
 
     # --------
     # Commands
diff --git a/tangostationcontrol/tangostationcontrol/devices/docker_device.py b/tangostationcontrol/tangostationcontrol/devices/docker_device.py
index b98bf53e95c65a12c5cdbc224f43d4acd674f4de..8ee1301c6eeb89d91fa166bc4691a9d84b0bb77a 100644
--- a/tangostationcontrol/tangostationcontrol/devices/docker_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/docker_device.py
@@ -43,30 +43,60 @@ class Docker(lofar_device):
     # ----------
     # Attributes
     # ----------
-    archiver_timescale_R = attribute_wrapper(comms_annotation={"container": "archiver-timescale"}, datatype=bool)
-    archiver_timescale_RW = attribute_wrapper(comms_annotation={"container": "archiver-timescale"}, datatype=bool, access=AttrWriteType.READ_WRITE)
-    databaseds_R = attribute_wrapper(comms_annotation={"container": "databaseds"}, datatype=bool)
-    databaseds_RW = attribute_wrapper(comms_annotation={"container": "databaseds"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+
+    # Software devices
+    device_boot_R = attribute_wrapper(comms_annotation={"container": "device-boot"}, datatype=bool)
+    device_boot_RW = attribute_wrapper(comms_annotation={"container": "device-boot"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_docker_R = attribute_wrapper(comms_annotation={"container": "device-docker"}, datatype=bool)
+    # device_docker_RW is not available, as we cannot start our own container`
+    device_temperature_manager_R = attribute_wrapper(comms_annotation={"container": "device-temperature-manager"}, datatype=bool)
+    device_temperature_manager_RW = attribute_wrapper(comms_annotation={"container": "device-temperature-manager"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_observation_R = attribute_wrapper(comms_annotation={"container": "device-observation"}, datatype=bool)
+    device_observation_RW = attribute_wrapper(comms_annotation={"container": "device-observation"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_observation_control_R = attribute_wrapper(comms_annotation={"container": "device-observation-control"}, datatype=bool)
+    device_observation_control_RW = attribute_wrapper(comms_annotation={"container": "device-observation-control"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+
+    # Hardware devices
     device_apsct_R = attribute_wrapper(comms_annotation={"container": "device-apsct"}, datatype=bool)
     device_apsct_RW = attribute_wrapper(comms_annotation={"container": "device-apsct"}, datatype=bool, access=AttrWriteType.READ_WRITE)
     device_apspu_R = attribute_wrapper(comms_annotation={"container": "device-apspu"}, datatype=bool)
     device_apspu_RW = attribute_wrapper(comms_annotation={"container": "device-apspu"}, datatype=bool, access=AttrWriteType.READ_WRITE)
-    device_beam_R = attribute_wrapper(comms_annotation={"container": "device-beam"}, datatype=bool)
-    device_beam_RW = attribute_wrapper(comms_annotation={"container": "device-beam"}, datatype=bool, access=AttrWriteType.READ_WRITE)
-    device_boot_R = attribute_wrapper(comms_annotation={"container": "device-boot"}, datatype=bool)
-    device_boot_RW = attribute_wrapper(comms_annotation={"container": "device-boot"}, datatype=bool, access=AttrWriteType.READ_WRITE)
     device_recv_R = attribute_wrapper(comms_annotation={"container": "device-recv"}, datatype=bool)
     device_recv_RW = attribute_wrapper(comms_annotation={"container": "device-recv"}, datatype=bool, access=AttrWriteType.READ_WRITE)
     device_sdp_R = attribute_wrapper(comms_annotation={"container": "device-sdp"}, datatype=bool)
     device_sdp_RW = attribute_wrapper(comms_annotation={"container": "device-sdp"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_unb2_R = attribute_wrapper(comms_annotation={"container": "device-unb2"}, datatype=bool)
+    device_unb2_RW = attribute_wrapper(comms_annotation={"container": "device-unb2"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_pcon_R = attribute_wrapper(comms_annotation={"container": "device-pcon"}, datatype=bool)
+    device_pcon_RW = attribute_wrapper(comms_annotation={"container": "device-pcon"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_psoc_R = attribute_wrapper(comms_annotation={"container": "device-psoc"}, datatype=bool)
+    device_psoc_RW = attribute_wrapper(comms_annotation={"container": "device-psoc"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_ccd_R = attribute_wrapper(comms_annotation={"container": "device-ccd"}, datatype=bool)
+    device_ccd_RW = attribute_wrapper(comms_annotation={"container": "device-ccd"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+
+    # Statistics devices
     device_sst_R = attribute_wrapper(comms_annotation={"container": "device-sst"}, datatype=bool)
     device_sst_RW = attribute_wrapper(comms_annotation={"container": "device-sst"}, datatype=bool, access=AttrWriteType.READ_WRITE)
     device_xst_R = attribute_wrapper(comms_annotation={"container": "device-xst"}, datatype=bool)
     device_xst_RW = attribute_wrapper(comms_annotation={"container": "device-xst"}, datatype=bool, access=AttrWriteType.READ_WRITE)
-    device_unb2_R = attribute_wrapper(comms_annotation={"container": "device-unb2"}, datatype=bool)
-    device_unb2_RW = attribute_wrapper(comms_annotation={"container": "device-unb2"}, datatype=bool, access=AttrWriteType.READ_WRITE)
-    device_docker_R = attribute_wrapper(comms_annotation={"container": "device-docker"}, datatype=bool)
-    # device_docker_RW is not available, as we cannot start our own container`
+    device_bst_R = attribute_wrapper(comms_annotation={"container": "device-bst"}, datatype=bool)
+    device_bst_RW = attribute_wrapper(comms_annotation={"container": "device-bst"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+
+    # Beam devices
+    device_antennafield_R = attribute_wrapper(comms_annotation={"container": "device-antennafield"}, datatype=bool)
+    device_antennafield_RW = attribute_wrapper(comms_annotation={"container": "device-antennafield"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_beamlet_R = attribute_wrapper(comms_annotation={"container": "device-beamlet"}, datatype=bool)
+    device_beamlet_RW = attribute_wrapper(comms_annotation={"container": "device-beamlet"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_digitalbeam_R = attribute_wrapper(comms_annotation={"container": "device-digitalbeam"}, datatype=bool)
+    device_digitalbeam_RW = attribute_wrapper(comms_annotation={"container": "device-digitalbeam"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_tilebeam_R = attribute_wrapper(comms_annotation={"container": "device-tilebeam"}, datatype=bool)
+    device_tilebeam_RW = attribute_wrapper(comms_annotation={"container": "device-tilebeam"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+
+    # Other containers
+    archiver_timescale_R = attribute_wrapper(comms_annotation={"container": "archiver-timescale"}, datatype=bool)
+    archiver_timescale_RW = attribute_wrapper(comms_annotation={"container": "archiver-timescale"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    databaseds_R = attribute_wrapper(comms_annotation={"container": "databaseds"}, datatype=bool)
+    databaseds_RW = attribute_wrapper(comms_annotation={"container": "databaseds"}, datatype=bool, access=AttrWriteType.READ_WRITE)
     dsconfig_R = attribute_wrapper(comms_annotation={"container": "dsconfig"}, datatype=bool)
     dsconfig_RW = attribute_wrapper(comms_annotation={"container": "dsconfig"}, datatype=bool, access=AttrWriteType.READ_WRITE)
     elk_R = attribute_wrapper(comms_annotation={"container": "elk"}, datatype=bool)
@@ -81,12 +111,14 @@ class Docker(lofar_device):
     itango_RW = attribute_wrapper(comms_annotation={"container": "itango"}, datatype=bool, access=AttrWriteType.READ_WRITE)
     jupyter_R = attribute_wrapper(comms_annotation={"container": "jupyter"}, datatype=bool)
     jupyter_RW = attribute_wrapper(comms_annotation={"container": "jupyter"}, datatype=bool, access=AttrWriteType.READ_WRITE)
-    prometheus_R = attribute_wrapper(comms_annotation={"container": "prometheus"}, datatype=bool)
-    prometheus_RW = attribute_wrapper(comms_annotation={"container": "prometheus"}, datatype=bool, access=AttrWriteType.READ_WRITE)
     tangodb_R = attribute_wrapper(comms_annotation={"container": "tangodb"}, datatype=bool)
     tangodb_RW = attribute_wrapper(comms_annotation={"container": "tangodb"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    prometheus_R = attribute_wrapper(comms_annotation={"container": "prometheus"}, datatype=bool)
+    prometheus_RW = attribute_wrapper(comms_annotation={"container": "prometheus"}, datatype=bool, access=AttrWriteType.READ_WRITE)
     tango_prometheus_exporter_R = attribute_wrapper(comms_annotation={"container": "tango-prometheus-exporter"}, datatype=bool)
     tango_prometheus_exporter_RW = attribute_wrapper(comms_annotation={"container": "tango-prometheus-exporter"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    prometheus_node_exporter_R = attribute_wrapper(comms_annotation={"container": "prometheus-node-exporter"}, datatype=bool)
+    prometheus_node_exporter_RW = attribute_wrapper(comms_annotation={"container": "prometheus-node-exporter"}, datatype=bool, access=AttrWriteType.READ_WRITE)
     tango_rest_R = attribute_wrapper(comms_annotation={"container": "tango-rest"}, datatype=bool)
     tango_rest_RW = attribute_wrapper(comms_annotation={"container": "tango-rest"}, datatype=bool, access=AttrWriteType.READ_WRITE)
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
index 068c9cee675f57f8a503fe8f4036bc2e98b80433..f950ad142ed6070ec5303223769cf77e189578db 100644
--- a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
@@ -10,8 +10,6 @@
 """Hardware Device Server for LOFAR2.0
 
 """
-
-from collections.abc import Sequence
 import time
 import math
 from typing import List
@@ -26,8 +24,10 @@ from tango import AttrWriteType, DevState, DebugIt, Attribute, DeviceProxy, Attr
 # Additional import
 from tangostationcontrol import __version__ as version
 from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
+
 from tangostationcontrol.common.lofar_logging import log_exceptions
 from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES, INITIALISED_STATES
+from tangostationcontrol.common.type_checking import sequence_not_str
 from tangostationcontrol.devices.device_decorators import only_in_states, fault_on_error
 from tangostationcontrol.toolkit.archiver import Archiver
 
@@ -38,14 +38,6 @@ import logging
 logger = logging.getLogger()
 
 
-# TODO(Corne): Remove this in L2SS-940
-def sequence_not_str(obj):
-    """Separate sequences / collections from str, byte or bytearray"""
-
-    return (isinstance(obj, Sequence) or isinstance(obj, numpy.ndarray)) and not \
-        isinstance(obj, (str, bytes, bytearray))
-
-
 class lofar_device(Device, metaclass=DeviceMeta):
     """
 
@@ -106,54 +98,104 @@ class lofar_device(Device, metaclass=DeviceMeta):
 
     # TODO(Corne): Actually implement locking in L2SS-940
     def atomic_read_modify_write_attribute(
-        self, values: numpy.ndarray, proxy: DeviceProxy, attribute: str, sparse=None
+        self, values: numpy.ndarray, proxy: DeviceProxy, attribute: str,
+        mask_or_sparse=None, cast_type=None
     ):
-        """Atomatically read-modify-write the attribute on the given proxy"""
+        """Automatically read-modify-write the attribute on the given proxy
 
+        :param values: New values to write
+        :param proxy: Device to write the values to
+        :param attribute: Attribute of the device to write
+        :param mask_or_sparse: The value or mask used to replace elements in
+                               values with current attribute values
+        :param cast_type: type to cast numpy array to for delimited merge_writes
+
+        """
+
+        # proxy.lock()
         current_values = proxy.read_attribute(attribute).value
-        self.merge_write(values, current_values, sparse)
-        proxy.write_attribute(attribute, values)
+        merged_values = self.merge_write(
+            values, current_values, mask_or_sparse, cast_type
+        )
+        proxy.write_attribute(attribute, merged_values)
+        # proxy.unlock()
 
-    # TODO(Corne): Update docstring in L2SS-940
     def merge_write(
-        self, merge_values: List[any], current_values: List[any], mask_or_sparse=None
-    ):
-        """Merge values as retrieved from :py:func:`~map_write` with current_values
+        self, merge_values: numpy.ndarray, current_values: List[any],
+        mask_or_sparse=None, cast_type=None
+    ) -> numpy.ndarray:
+        """Merge values with current_values retrieved from attribute by mask / sparse
 
-        This method will modify the contents of merge_values.
+        To be used by the :py:func:`~atomic_read_modify_write_attribute`
 
-        To be used by the :py:class:`~AntennaField` device to remove sparse fields
-        from mapped_values with recently retrieved current_values from RECV device.
+        :param merge_values: New values to write and results of merge
+        :param current_values: values retrieved from an attribute
+        :param mask_or_sparse: The value or mask used to replace elements in
+                               merge_values with current_values
+        :param cast_type: type to cast numpy array to for delimited merge_writes
+        :return:
 
-        :param merge_values: values as retrieved from :py:func:`~map_write`
-        :param current_values: values retrieved from RECV device on specific attribute
-        :param sparse: The value to identify sparse entries
         """
 
+        # Create shallow copy of merge_values, use native numpy copy as it works
+        # for N dimensionality. (native copy.copy() only copies outermost dim)
+        merge_values = merge_values.copy()
+
         if mask_or_sparse is not None and sequence_not_str(mask_or_sparse):
             self._merge_write_mask(
                 merge_values, current_values, mask_or_sparse
             )
+            return merge_values
         else:
+            if cast_type is None:
+                raise AttributeError(
+                    "dtype can not be None for sparse merge_write"
+                )
+
             self._merge_write_delimiter(
                 merge_values, current_values, mask_or_sparse
             )
+            return merge_values.astype(dtype=cast_type)
 
     def _merge_write_delimiter(
-        self, merge_values: List[any], current_values: List[any], sparse=None
+        self, merge_values: numpy.ndarray, current_values: List[any],
+        sparse=None,
     ):
+        """Merge merge_values and current_values by replacing elements by sparse
+
+        For every element in merge_values where the value is equal to sparse
+        replace it by the element in current_values.
+
+        The result can be obtained in merge_values as the list is modified
+        in-place (and passed by reference).
+        """
+
         for idx, value in enumerate(merge_values):
             if sequence_not_str(value):
-                self._merge_write_delimiter(merge_values[idx], current_values[idx], sparse)
+                self._merge_write_delimiter(
+                    merge_values[idx], current_values[idx], sparse
+                )
             elif value == sparse:
                 merge_values[idx] = current_values[idx]
 
     def _merge_write_mask(
-        self, merge_values: List[any], current_values: List[any], mask: List[any]
+        self, merge_values: List[any], current_values: List[any],
+        mask: List[any]
     ):
+        """Merge merge_values and current_values by replacing elements by mask
+
+        For every element in merge_values where the element in mask is false
+        replace it by the element in current_values.
+
+        The result can be obtained in merge_values as the list is modified
+        in-place (and passed by reference).
+        """
+
         for idx, value in enumerate(merge_values):
             if sequence_not_str(value):
-                self._merge_write_mask(merge_values[idx], current_values[idx], mask[idx])
+                self._merge_write_mask(
+                    merge_values[idx], current_values[idx], mask[idx]
+                )
             elif not mask[idx]:
                 merge_values[idx] = current_values[idx]
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/recv.py b/tangostationcontrol/tangostationcontrol/devices/recv.py
index aeaa506c3d0cca422426db7316dd095bc34e7de6..a1bae7c07266e4b37a7993a5472886f74424737c 100644
--- a/tangostationcontrol/tangostationcontrol/devices/recv.py
+++ b/tangostationcontrol/tangostationcontrol/devices/recv.py
@@ -63,13 +63,19 @@ class RECV(opcua_device):
         default_value=[True] * 32
     )
 
+    RCU_attenuator_dB_RW_default = device_property(
+        dtype='DevVarLong64Array',
+        mandatory=False,
+        default_value=[0] * 96
+    )
+
     RCU_band_select_RW_default = device_property(
         dtype='DevVarLong64Array',
         mandatory=False,
         default_value=[0] * 96
     )
 
-    RCU_PWR_ANT_on_RW = device_property(
+    RCU_PWR_ANT_on_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
         default_value=[False] * 96 # turn power off by default in test setups, f.e. to prevent blowing up the noise sources
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
index d35701ee4821919631a3c4b791c631ca142ae4f0..a87c6b6e00b06ccfe4275055db5772b036dd8995 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
@@ -59,20 +59,20 @@ class SDP(opcua_device):
 
     # If we enable the waveform generator, we want some sane defaults.
 
-    FPGA_wg_amplitude_RW = device_property(
+    FPGA_wg_amplitude_RW_default = device_property(
         dtype='DevVarDoubleArray',
         mandatory=False,
         default_value=[[0.1] * 12] * 16
     )
 
-    FPGA_wg_frequency_RW = device_property(
+    FPGA_wg_frequency_RW_default = device_property(
         dtype='DevVarDoubleArray',
         mandatory=False,
         # Emit a signal on subband 102
         default_value=[[102 * 200e6/1024] * 12] * 16
     )
 
-    FPGA_wg_phase_RW = device_property(
+    FPGA_wg_phase_RW_default = device_property(
         dtype='DevVarDoubleArray',
         mandatory=False,
         default_value=[[0.0] * 12] * 16
diff --git a/tangostationcontrol/tangostationcontrol/devices/unb2.py b/tangostationcontrol/tangostationcontrol/devices/unb2.py
index ba0c1364efe3af800ca0a3cf3ae7be313d1a38ac..b64b86b0e344d0b6642fb6364ff31ae983fbece9 100644
--- a/tangostationcontrol/tangostationcontrol/devices/unb2.py
+++ b/tangostationcontrol/tangostationcontrol/devices/unb2.py
@@ -63,12 +63,6 @@ class UNB2(opcua_device):
     N_DDR = 2
     N_QSFP = 6
 
-    UNB2_mask_RW_default = device_property(
-        dtype='DevVarBooleanArray',
-        mandatory=False,
-        default_value=[True] * 2
-    )
-
     TRANSLATOR_DEFAULT_SETTINGS = [
         'UNB2_mask_RW',
         'UNB2TR_monitor_rate_RW'
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/statistics/test_writer_sst.py b/tangostationcontrol/tangostationcontrol/integration_test/default/statistics/test_writer_sst.py
index dfb548d3ed0b8d51edab43d2c74b280cf40c0162..f1cf4f3154cbdbe75e8abb96994e2c5e0ecc1f98 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/default/statistics/test_writer_sst.py
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/statistics/test_writer_sst.py
@@ -82,7 +82,7 @@ class TestStatisticsWriterSST(BaseIntegrationTestCase):
                     '2021-09-20T12:17:40.000+00:00'
                 )
                 self.assertIsNotNone(stat)
-                self.assertEqual("0.1", stat.station_version_id)
+                self.assertEqual("0.1.1", stat.station_version_id)
                 self.assertEqual("0.1", stat.writer_version_id)
     
     def test_insert_tango_SST_statistics(self):
@@ -181,7 +181,7 @@ class TestStatisticsWriterSST(BaseIntegrationTestCase):
                 )
                 self.assertIsNotNone(stat)
                 self.assertEqual(121, stat.data_id_signal_input_index)
-                # Test RECV attributes      
+                # Test RECV attributes
                 self.assertEqual(stat.rcu_attenuator_dB, None)
                 self.assertEqual(stat.rcu_band_select, None)
                 self.assertEqual(stat.rcu_dth_on, None)
diff --git a/tangostationcontrol/tangostationcontrol/statistics/reader.py b/tangostationcontrol/tangostationcontrol/statistics/reader.py
index efed9b52d0ffcac726284eb53db2306898a79403..1ab326db03bf8fdb1b773ce3471cb0ddbe287846 100644
--- a/tangostationcontrol/tangostationcontrol/statistics/reader.py
+++ b/tangostationcontrol/tangostationcontrol/statistics/reader.py
@@ -202,25 +202,14 @@ class statistics_data:
 
         # get SST specific stuff
         if self.marker == "S":
-
             self.data_id_signal_input_index = file[group_key].attrs["data_id_signal_input_index"]
-
             # check if the dataset is empty or not. if empty, set to None, if not get the value
-
-            if file.get(f'{group_key}/rcu_attenuator_dB').shape is None:
-                self.rcu_attenuator_dB = None
-            else:
-                self.rcu_attenuator_dB = numpy.array(file.get(f"{group_key}/rcu_attenuator_dB"))
-
-            if file.get(f'{group_key}/rcu_band_select').shape is None:
-                self.rcu_band_select = None
-            else:
-                self.rcu_band_select = numpy.array(file.get(f"{group_key}/rcu_band_select"))
-
-            if file.get(f'{group_key}/rcu_dth_on').shape is None:
-                self.rcu_dth_on = None
-            else:
-                self.rcu_dth_on = numpy.array(file.get(f"{group_key}/rcu_dth_on"))
+            attribute_names = ["rcu_attenuator_dB", "rcu_band_select", "rcu_dth_on"]
+            for a in attribute_names:
+                if file[group_key].attrs[a].shape is None:
+                    setattr(self, a, None) 
+                else :
+                    setattr(self, a, numpy.array(file[group_key].attrs[a]))
 
         # get XST specific stuff
         if self.marker == "X":
diff --git a/tangostationcontrol/tangostationcontrol/statistics/writer/hdf5.py b/tangostationcontrol/tangostationcontrol/statistics/writer/hdf5.py
index 3906f436c1acce5beaad45b2f265c6f86fb7fbf8..f1da6a4c5930599973b9f18ad17e8b6f2a28fc9f 100644
--- a/tangostationcontrol/tangostationcontrol/statistics/writer/hdf5.py
+++ b/tangostationcontrol/tangostationcontrol/statistics/writer/hdf5.py
@@ -87,6 +87,7 @@ class HDF5Writer(ABC):
 
         # Set device if any, defaults to None
         self.device = device
+        self.device_attributes = {}
 
     @abstractmethod
     def decoder(self, packet):
@@ -169,6 +170,8 @@ class HDF5Writer(ABC):
         # write the finished (and checks if its the first matrix)
         if self.current_matrix is not None:
             try:
+                # query the device attributes for updated values
+                self.retrieve_attribute_values()
                 self.write_matrix()
             except Exception as e:
                 time = self.current_timestamp.strftime(
@@ -187,6 +190,7 @@ class HDF5Writer(ABC):
         # create a new and empty current_matrix
         self.current_matrix = self.new_collector()
         self.statistics_header = None
+        self.device_attributes = {}
 
     def write_matrix(self):
         """Writes the finished matrix to the hdf5 file"""
@@ -238,6 +242,10 @@ class HDF5Writer(ABC):
             else:
                 current_group.attrs[k] = v
 
+    @abstractmethod
+    def retrieve_attribute_values(self):
+        pass
+    
     @abstractmethod
     def write_values_matrix(self, current_group):
         pass
@@ -322,6 +330,19 @@ class SstHdf5Writer(HDF5Writer):
 
     def new_collector(self):
         return StationSSTCollector(self.device)
+    
+    def retrieve_attribute_values(self):
+        attribute_names = ["rcu_attenuator_dB", "rcu_band_select", "rcu_dth_on"]
+        attribute_types = {"rcu_attenuator_dB": numpy.int64, "rcu_band_select" : numpy.int64, "rcu_dth_on" : bool}
+        # write the device attributes
+        for a in attribute_names:
+            try:
+                if self.current_matrix.parameters[a] is None:
+                    self.device_attributes[a] = h5py.Empty("f")
+                else:
+                    self.device_attributes[a] = self.current_matrix.parameters[a].flatten().astype(attribute_types[a])                 
+            except AttributeError:
+                self.device_attributes[a] = h5py.Empty("f")
 
     def write_values_matrix(self, current_group):
         # store the SST values
@@ -333,43 +354,8 @@ class SstHdf5Writer(HDF5Writer):
             compression="gzip",
         )
 
-        try:
-            current_group.create_dataset(
-                name="rcu_attenuator_dB",
-                data=self.current_matrix.parameters["rcu_attenuator_dB"].astype(numpy.int64),
-                compression="gzip",
-            )
-        except AttributeError:
-            current_group.create_dataset(
-                name="rcu_attenuator_dB",
-                data=h5py.Empty("f"),
-            )
-
-        try:
-            current_group.create_dataset(
-                name="rcu_band_select",
-                data=self.current_matrix.parameters["rcu_band_select"].astype(numpy.int64),
-                compression="gzip",
-            )
-        except AttributeError:
-            current_group.create_dataset(
-                name="rcu_band_select",
-                data=h5py.Empty("f"),
-            )
-
-        try:
-            current_group.create_dataset(
-                name="rcu_dth_on",
-                data=self.current_matrix.parameters["rcu_dth_on"].astype(numpy.bool_),
-                compression="gzip",
-            )
-        except AttributeError:
-            current_group.create_dataset(
-                name="rcu_dth_on",
-                data=h5py.Empty("f"),
-            )
-
-
+        for k,v in self.device_attributes.items():
+            current_group.attrs[k] = v
 
 class BstHdf5Writer(HDF5Writer):
     def __init__(
@@ -387,6 +373,9 @@ class BstHdf5Writer(HDF5Writer):
 
     def new_collector(self):
         return BSTCollector()
+    
+    def retrieve_attribute_values(self):
+        pass
 
     def write_values_matrix(self, current_group):
         # store the BST values
@@ -427,6 +416,9 @@ class XstHdf5Writer(HDF5Writer):
             f"{self.file_location}/{self.mode}_SB{self.subband_index}_"
             f"{time_str}{suffix}"
         )
+    
+    def retrieve_attribute_values(self):
+        pass
 
     def write_values_matrix(self, current_group):
         # requires a function call to transform the xst_blocks in to the right
diff --git a/tangostationcontrol/tangostationcontrol/test/common/test_type_checking.py b/tangostationcontrol/tangostationcontrol/test/common/test_type_checking.py
new file mode 100644
index 0000000000000000000000000000000000000000..253fb6182006a426188e84576bf295344f973549
--- /dev/null
+++ b/tangostationcontrol/tangostationcontrol/test/common/test_type_checking.py
@@ -0,0 +1,77 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of the LOFAR 2.0 Station Software
+#
+#
+#
+# Distributed under the terms of the APACHE license.
+# See LICENSE.txt for more info.
+import numpy
+
+from tangostationcontrol.common import type_checking
+
+from tangostationcontrol.test import base
+
+
+class TestTypeChecking(base.TestCase):
+
+    @staticmethod
+    def subscriptable(obj):
+        return hasattr(obj, '__getitem__')
+
+    @staticmethod
+    def iterable(obj):
+        return hasattr(obj, '__iter__')
+
+    @staticmethod
+    def positional_ordering(obj):
+        try:
+            obj[0]
+            return True
+        except Exception:
+            return False
+
+    def sequence_test(self, obj):
+        """Test object is sequence based on properties and verify is_sequence"""
+
+        result = (
+            self.subscriptable(obj) & self.iterable(obj)
+            & self.positional_ordering(obj)
+        )
+
+        self.assertEqual(
+            result, type_checking.is_sequence(obj),
+            F"Test failed for type {type(obj)}"
+        )
+
+    def test_is_sequence_for_types(self):
+        """Types to be tested by is_sequence"""
+
+        test_types = [
+            (False,),
+            {"test": "test"},
+            [False],
+            {"test"},
+            numpy.array([1, 2, 3]),
+        ]
+
+        for test in test_types:
+            self.sequence_test(test)
+
+    def test_is_sequence_not_str(self):
+        """Types test for sequence_not_str, must be false"""
+
+        t_bytearray = bytearray([0, 5, 255])
+        test_types = [
+            str(""),
+            bytes(t_bytearray),
+            t_bytearray
+        ]
+
+        for test in test_types:
+            self.assertFalse(type_checking.sequence_not_str(test))
+
+    def test_type_not_sequence(self):
+        test = [str]
+        self.assertFalse(type_checking.type_not_sequence(test))
+        self.assertTrue(type_checking.type_not_sequence(test[0]))
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/test_antennafield_device.py b/tangostationcontrol/tangostationcontrol/test/devices/test_antennafield_device.py
index 85d10cfab14fe784e250694d08afd6b9fbe2b2ac..23e08c71bb07db68319b8795d90cfcacc0846810 100644
--- a/tangostationcontrol/tangostationcontrol/test/devices/test_antennafield_device.py
+++ b/tangostationcontrol/tangostationcontrol/test/devices/test_antennafield_device.py
@@ -7,8 +7,6 @@
 # Distributed under the terms of the APACHE license.
 # See LICENSE.txt for more info.
 
-import time
-import statistics
 import logging
 
 import unittest
@@ -345,43 +343,43 @@ class TestAntennaToRecvMapper(base.TestCase):
         actual = mapper.map_write("HBAT_PWR_on_RW", set_values)
         numpy.testing.assert_equal(expected, actual)
 
-    def test_merge_write(self):
-        """Verify all None fields are replaced by merge_write if no control"""
-
-        mapper = AntennaToRecvMapper(
-            self.CONTROL_NOT_CONNECTED, self.POWER_NOT_CONNECTED, 1
-        )
-
-        merge_values = [[None] * 32] * 96
-        current_values = [[False] * 32] * 96
-
-        mapper.merge_write(merge_values, current_values)
-        numpy.testing.assert_equal(merge_values, current_values)
-
-        results = []
-        for _i in range(25):
-            start_time = time.monotonic_ns()
-            mapper.merge_write(merge_values, current_values)
-            stop_time = time.monotonic_ns()
-            results.append(stop_time - start_time)
-
-        logging.error(
-            f"Merge write performance: Median {statistics.median(results) / 1.e9} "
-            f"Stdev {statistics.stdev(results) / 1.e9}"
-        )
-
-    def test_merge_write_values(self):
-        """Verify all fields with values are retained by merge_write"""
-
-        mapper = AntennaToRecvMapper(
-            self.CONTROL_NOT_CONNECTED, self.POWER_NOT_CONNECTED, 1
-        )
-
-        merge_values = [[True] * 32] * 2 + [[None] * 32] * 94
-        current_values = [[True] * 32] * 2 + [[False] * 32] * 94
-
-        mapper.merge_write(merge_values, current_values)
-        numpy.testing.assert_equal(merge_values, current_values)
+    # def test_merge_write(self):
+    #     """Verify all None fields are replaced by merge_write if no control"""
+    #
+    #     mapper = AntennaToRecvMapper(
+    #         self.CONTROL_NOT_CONNECTED, self.POWER_NOT_CONNECTED, 1
+    #     )
+    #
+    #     merge_values = [[None] * 32] * 96
+    #     current_values = [[False] * 32] * 96
+    #
+    #     mapper.merge_write(merge_values, current_values)
+    #     numpy.testing.assert_equal(merge_values, current_values)
+    #
+    #     results = []
+    #     for _i in range(25):
+    #         start_time = time.monotonic_ns()
+    #         mapper.merge_write(merge_values, current_values)
+    #         stop_time = time.monotonic_ns()
+    #         results.append(stop_time - start_time)
+    #
+    #     logging.error(
+    #         f"Merge write performance: Median {statistics.median(results) / 1.e9} "
+    #         f"Stdev {statistics.stdev(results) / 1.e9}"
+    #     )
+    #
+    # def test_merge_write_values(self):
+    #     """Verify all fields with values are retained by merge_write"""
+    #
+    #     mapper = AntennaToRecvMapper(
+    #         self.CONTROL_NOT_CONNECTED, self.POWER_NOT_CONNECTED, 1
+    #     )
+    #
+    #     merge_values = [[True] * 32] * 2 + [[None] * 32] * 94
+    #     current_values = [[True] * 32] * 2 + [[False] * 32] * 94
+    #
+    #     mapper.merge_write(merge_values, current_values)
+    #     numpy.testing.assert_equal(merge_values, current_values)
 
 
 class TestAntennafieldDevice(device_base.DeviceTestCase):
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/test_lofar_device.py b/tangostationcontrol/tangostationcontrol/test/devices/test_lofar_device.py
index 38d599f9f780cccd2d506a588ae8a2596f5f5ff8..3c66e6176d127acd1120f7da2f7373f37d095651 100644
--- a/tangostationcontrol/tangostationcontrol/test/devices/test_lofar_device.py
+++ b/tangostationcontrol/tangostationcontrol/test/devices/test_lofar_device.py
@@ -66,3 +66,17 @@ class TestLofarDevice(device_base.DeviceTestCase):
             with self.assertRaises(DevFailed):
                 proxy.disable_hardware()
 
+    def test_atomic_read_modify_write(self):
+        """Test atomic read modify write for attribute"""
+
+        class AttributeLofarDevice(lofar_device.lofar_device):
+
+            BOOL_ARRAY_DIM = 32
+
+            # Just for demo, do not use class variables to store attribute state
+            _bool_array = [False] * BOOL_ARRAY_DIM
+
+
+            @attribute(dtype=(bool,), max_dim_x=BOOL_ARRAY_DIM)
+            def bool_array(self):
+                return self._bool_array