diff --git a/docker-compose/Makefile b/docker-compose/Makefile
index a725ea8d3e863add90c29f1a35c6745cbd64575d..6961532bf0002e1379744ea1ed9f177e7fdd89fe 100644
--- a/docker-compose/Makefile
+++ b/docker-compose/Makefile
@@ -160,7 +160,7 @@ DOCKER_COMPOSE_ARGS := DISPLAY=$(DISPLAY) \
     TEST_MODULE=$(INTEGRATION_MODULE)
 
 
-.PHONY: up down minimal context run integration start stop restart build build-nocache status clean pull help
+.PHONY: up down minimal context run integration start stop restart build build-nocache status clean pull help await
 .DEFAULT_GOAL := help
 
 pull: ## pull the images from the Docker hub
@@ -224,17 +224,18 @@ restart: ## restart a service (usage: make restart <servicename>)
 attach:  ## attach a service to an existing Tango network
 	$(DOCKER_COMPOSE_ARGS) docker-compose $(ATTACH_COMPOSE_FILE_ARGS) up --no-recreate -d $(SERVICE)
 
-time := 0
+TIME := 0
 await:  ## Await every container with total max timeout of 300, do not reset timeout
+	time=$(TIME); \
 	for i in $(SERVICE); do \
 		current_service=$$($(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) ps -q $${i}); \
 		if [ -z "$${current_service}" ]; then \
-		    continue; \
-        fi; \
-        service_has_health=$$(docker inspect -f '{{.State.Health.Status}}' $${current_service}); \
-        if [ -z "$${service_has_health}" ]; then \
-            continue; \
-        fi; \
+			continue; \
+		fi; \
+		service_has_health=$$(docker inspect -f '{{.State.Health.Status}}' $${current_service}); \
+		if [ -z "$${service_has_health}" ]; then \
+			continue; \
+		fi; \
 		while [ "$$(docker inspect -f '{{.State.Health.Status}}' $${current_service})" != "healthy" ] ; do \
 			sleep 1; \
 			time=$$(expr $$time + 1); \
diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh
index 046f0ab4a4926df0731aa6f55ca0e60221ba387e..6c95dc8dda9c9c3a6755a38f6a4f5e6a71de094e 100755
--- a/sbin/run_integration_test.sh
+++ b/sbin/run_integration_test.sh
@@ -31,6 +31,8 @@ function integration_test {
     # shellcheck disable=SC2145
     echo "make restart ${restarts[@]} ..."
     make restart "${restarts[@]}"
+    # shellcheck disable=SC2145
+    echo "make await ${restarts[@]} ..."
     make await "${restarts[@]}"
   fi
 
@@ -86,13 +88,11 @@ SIMULATORS=(sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim ccd-sim)
 # take really long to finish, especially grafana / jupyter / prometheus.
 # jupyter is physically large > 2.5gb and overlayfs is really slow.
 
-# shellcheck disable=SC2086
 make build "${DEVICES[@]}" "${SIMULATORS[@]}"
 make build logstash integration-test schemas
 make build archiver-timescale hdbppts-cm hdbppts-es
 
 # Start and stop sequence
-# shellcheck disable=SC2086
 make stop schemas
 make stop "${DEVICES[@]}" "${SIMULATORS[@]}" hdbppts-es hdbppts-cm archiver-timescale
 make stop device-docker # this one does not test well in docker-in-docker
@@ -117,7 +117,6 @@ bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/stations/simu
 bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/stations/dummy_positions_ConfigDb.json
 
 cd "$LOFAR20_DIR/docker-compose" || exit 1
-# shellcheck disable=SC2086
 make start "${SIMULATORS[@]}"
 
 # Give the simulators time to start
diff --git a/tangostationcontrol/tangostationcontrol/clients/README.md b/tangostationcontrol/tangostationcontrol/clients/README.md
index 9a0c749575c32ad6d582427f154562d97a7fc8a6..a68efcd5d73ca2e3900c33666481111b0f159074 100644
--- a/tangostationcontrol/tangostationcontrol/clients/README.md
+++ b/tangostationcontrol/tangostationcontrol/clients/README.md
@@ -14,7 +14,7 @@ Inside lofar/tango/tangostationcontrol/tangostationcontrol/devices/lofar_device.
 	Dims:			Tuple of the dimensions (x,) or (x,y)
 	Access:		AttrWriteType.READ or AttrWriteType.READWRITE	, determines whether this is a read or read/write function. 	
 	Init_value:		Initialisation value. If none is presents, fills the attribute with zero  data of the correct type and dimension
-	**kwargs: any other non attribute_wrapper arguments.
+	**kwargs: any other non AttributeWrapper arguments.
 NOTE: the `__init__` function contains wrappers for the unassigned read/write functions. In previous versions the read function of an RW attribute used to return the last value it had written *to* the client  instead of the value from the client. This has since been changed.  
 	
 `set_comm_client`:
@@ -32,22 +32,22 @@ This function can be called to assign a read and write function to the attribute
 
 ## Example Device / usage
 Here an example of a Tango Device that uses the attribute wrapper is presented. 
-The device class is a sub-class of opcua_device, which is, in turn, a sub-class of lofar_device class which implements the attribute initialisation methods (attr_list and setup_value_dict ) as stated above.
+The device class is a sub-class of OPCUADevice, which is, in turn, a sub-class of lofar_device class which implements the attribute initialisation methods (attr_list and setup_value_dict ) as stated above.
 ```python
-class RECV(opcua_device):
+class RECV(OPCUADevice):
 
     # ----------
     # Attributes
     # ----------
     
     # Scalar attribute
-    RECVTR_translator_busy_R = attribute_wrapper(comms_annotation=["RECVTR_translator_busy_R"],datatype=bool)
+    RECVTR_translator_busy_R = AttributeWrapper(comms_annotation=["RECVTR_translator_busy_R"],datatype=bool)
     
     # Array attribute 
-    RCU_TEMP_R  = attribute_wrapper(comms_annotation=["RCU_TEMP_R"], datatype=numpy.float64, dims=(32,))
+    RCU_TEMP_R  = AttributeWrapper(comms_annotation=["RCU_TEMP_R"], datatype=numpy.float64, dims=(32,))
     
     # Image (2D array) attribute
-    HBAT_BF_delays_R = attribute_wrapper(comms_annotation=["HBAT_BF_delays_R" ],datatype=numpy.int64  , dims=(32,96))
+    HBAT_BF_delays_R = AttributeWrapper(comms_annotation=["HBAT_BF_delays_R" ],datatype=numpy.int64  , dims=(32,96))
 
 ```
 
@@ -64,9 +64,9 @@ Once the Tango device is up and running, one can interact with the device attrib
 Clients work by providing a communication interface or data accessor for the attribute. The implementation of this is largely up to the user, but must contain a `setup_attribute` function that returns a valid read and write function. 
 
 Once a client has been initialized, the attributes can be assigned their read/write functions. 
-To couple a client to an attribute the set_comm_client or async_set_comm_client of the attribute_wrapper can be called. This function then calls the `setup_attribute` function of the client.
+To couple a client to an attribute the set_comm_client or async_set_comm_client of the AttributeWrapper can be called. This function then calls the `setup_attribute` function of the client.
 
-Attributes can be given any custom data in the `Comms_annotation` argument during their creation. This data as well as the attribute_wrapper object itself can be accessed by the `setup_attribute` function in order to correctly configure the read/write functions. The read function should return a numpy array of the correct type and shape, while the write function has to take an input value, which will be of the type and shape of the attribute. 
+Attributes can be given any custom data in the `Comms_annotation` argument during their creation. This data as well as the AttributeWrapper object itself can be accessed by the `setup_attribute` function in order to correctly configure the read/write functions. The read function should return a numpy array of the correct type and shape, while the write function has to take an input value, which will be of the type and shape of the attribute. 
 
 Clients can be set up in the device, during the initialization and then can be assigned to the attributes by looping through the list of attributes and calling the `set_comm_client` function.
 
@@ -79,7 +79,7 @@ The attribute wrapper relies on 1 internal file. tango/tangostationcontrol/devic
 
 
 ## Closing
-The advantages of using attribute_wrapper class instead of the standard Tango Attribute class can be noted in the following example where, in the first part, an implementation of the standard class is presented, while in the second part the analogous implementation using an attribute_wrapper is shown.
+The advantages of using AttributeWrapper class instead of the standard Tango Attribute class can be noted in the following example where, in the first part, an implementation of the standard class is presented, while in the second part the analogous implementation using an attribute_wrapper is shown.
 
 ## From official Tango documentation
 ```python
diff --git a/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py b/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py
index 46589552326436c926c98750b91b9b42b8b52d4f..9f970cb306b6de791d756bc13b9ccc7082fb070a 100644
--- a/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py
+++ b/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py
@@ -11,7 +11,7 @@ import logging
 logger = logging.getLogger()
 
 
-class attribute_io(object):
+class AttributeIO(object):
     """ Holds the I/O functionality for an attribute for a specific device. """
 
     def __init__(self, device, attribute_wrapper):
@@ -60,7 +60,7 @@ class attribute_io(object):
         self.cached_value = value
 
 
-class attribute_wrapper(attribute):
+class AttributeWrapper(attribute):
     """
     Wraps all the attributes in a wrapper class to manage most of the redundant code behind the scenes
     """
@@ -196,7 +196,7 @@ class attribute_wrapper(attribute):
         try:
             return device._attribute_wrapper_io[self]
         except KeyError:
-            device._attribute_wrapper_io[self] = attribute_io(device, self)
+            device._attribute_wrapper_io[self] = AttributeIO(device, self)
             return device._attribute_wrapper_io[self]
 
     def set_comm_client(self, device, client):
diff --git a/tangostationcontrol/tangostationcontrol/clients/opcua_client.py b/tangostationcontrol/tangostationcontrol/clients/opcua_client.py
index 53211e52fea7472390d82c450543eb8351ca165f..15261dd922d3865631402ca8c1af5144bb856f0c 100644
--- a/tangostationcontrol/tangostationcontrol/clients/opcua_client.py
+++ b/tangostationcontrol/tangostationcontrol/clients/opcua_client.py
@@ -172,7 +172,7 @@ class OPCUAConnection(AsyncCommClient):
             logger.exception(f"Could not get node: {path} on server {self._servername()}")
             raise Exception(f"Could not get node: {path} on server {self._servername()}") from e
 
-        # get all the necessary data to set up the read/write functions from the attribute_wrapper
+        # get all the necessary data to set up the read/write functions from the AttributeWrapper
         dim_x = attribute.dim_x
         dim_y = attribute.dim_y
         ua_type = numpy_to_OPCua_dict[attribute.datatype] # convert the numpy type to a corresponding UA type
diff --git a/tangostationcontrol/tangostationcontrol/clients/snmp_client.py b/tangostationcontrol/tangostationcontrol/clients/snmp_client.py
index dbd9459ed617a167ef469742e33e08a580a532d3..b94292eb2067207695111740b668b990cda3467d 100644
--- a/tangostationcontrol/tangostationcontrol/clients/snmp_client.py
+++ b/tangostationcontrol/tangostationcontrol/clients/snmp_client.py
@@ -11,7 +11,7 @@ import logging
 
 logger = logging.getLogger()
 
-__all__ = ["SNMP_client"]
+__all__ = ["SNMPClient"]
 
 snmp_to_numpy_dict = {
     hlapi.Integer32: numpy.int64,
@@ -25,7 +25,7 @@ snmp_to_numpy_dict = {
 }
 
 
-class SNMP_comm:
+class SNMPComm:
     """
     Holds information for communicating with the SNMP server
     """
@@ -54,7 +54,7 @@ class SNMP_comm:
         return next(hlapi.setCmd(self.engine, self.community, self.transport, self.ctx_data, *objs))
 
 
-class SNMP_client(CommClient):
+class SNMPClient(CommClient):
     """
         messages to keep a check on the connection. On connection failure, reconnects once.
     """
@@ -69,7 +69,7 @@ class SNMP_client(CommClient):
         super().__init__(fault_func, try_interval)
 
         logger.debug(f"setting up SNMP engine with host: {host} and community: {community}")
-        self.SNMP_comm = SNMP_comm(community, host, version, port)
+        self.SNMP_comm = SNMPComm(community, host, version, port)
 
         # only sets up the engine, doesn't connect
         self.connected = True
@@ -92,7 +92,7 @@ class SNMP_client(CommClient):
 
     def setup_value_conversion(self, attribute):
         """
-        gives the client access to the attribute_wrapper object in order to access all data it could potentially need.
+        gives the client access to the AttributeWrapper object in order to access all data it could potentially need.
         """
 
         dim_x = attribute.dim_x
@@ -106,16 +106,16 @@ class SNMP_client(CommClient):
         MANDATORY function: is used by the attribute wrapper to get read/write functions. must return the read and write functions
 
         Gets called from inside the attribute wrapper. It is provided with the attribute_warpper itself
-        and the annotation provided when the attribute_wrapper was declared.
+        and the annotation provided when the AttributeWrapper was declared.
         These parameters can be used to configure a valid read and write function as return values.
         """
 
         # process the annotation
         mib, name, idx, scaling_factor = self._process_annotation(annotation)
 
-        # get all the necessary data to set up the read/write functions from the attribute_wrapper
+        # get all the necessary data to set up the read/write functions from the AttributeWrapper
         dim_x, dim_y, dtype = self.setup_value_conversion(attribute)
-        snmp_attr = snmp_attribute(self.SNMP_comm, mib, name, idx, dtype, dim_x, dim_y, scaling_factor)
+        snmp_attr = SNMPAttribute(self.SNMP_comm, mib, name, idx, dtype, dim_x, dim_y, scaling_factor)
 
         # return the read/write functions
         def read_function():
@@ -126,9 +126,9 @@ class SNMP_client(CommClient):
 
         return read_function, write_function
 
-class snmp_attribute:
+class SNMPAttribute:
 
-    def __init__(self, comm: SNMP_comm, mib, name, idx, dtype, dim_x, dim_y, scaling_factor=1):
+    def __init__(self, comm: SNMPComm, mib, name, idx, dtype, dim_x, dim_y, scaling_factor=1):
 
         self.comm = comm
         self.mib = mib
@@ -248,7 +248,7 @@ class snmp_attribute:
 
 
 
-class mib_loader:
+class MIBLoader:
 
     def __init__(self, mib_dir: str):
         self.mibBuilder = builder.MibBuilder()
diff --git a/tangostationcontrol/tangostationcontrol/common/health.py b/tangostationcontrol/tangostationcontrol/common/health.py
index ab7ed2815b72f5a20e9b5aa4283c472c18643833..688a534d145ba30ca4934731333e46fbde62ad5c 100644
--- a/tangostationcontrol/tangostationcontrol/common/health.py
+++ b/tangostationcontrol/tangostationcontrol/common/health.py
@@ -15,6 +15,7 @@ def main(*args, **kwargs):
 
     try:
         DeviceProxy(args[0]).ping()
+
         return 0
     except BaseException:
         return 1
diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/antennafield.py
index 2c89283f88c123042c1b8bc531b1623b374d62c8..e572803cb66cb747b6d6bff0a47a8aba3c40caf1 100644
--- a/tangostationcontrol/tangostationcontrol/devices/antennafield.py
+++ b/tangostationcontrol/tangostationcontrol/devices/antennafield.py
@@ -16,19 +16,22 @@ from tango import DeviceProxy, DevSource, AttrWriteType, DevVarFloatArray, DevVa
 from tango.server import device_property, attribute, command
 
 # Additional import
-from tangostationcontrol.common.type_checking import type_not_sequence
+from tangostationcontrol.beam.geo import ETRS_to_ITRF
+from tangostationcontrol.beam.geo import GEO_to_GEOHASH
+from tangostationcontrol.beam.geo import ITRF_to_GEO
+from tangostationcontrol.beam.hba_tile import HBATAntennaOffsets
+from tangostationcontrol.common.cables import cable_types
+from tangostationcontrol.common.calibration import delay_compensation
+from tangostationcontrol.common.calibration import loss_compensation
+from tangostationcontrol.common.constants import N_elements, MAX_ANTENNA, N_pol, N_xyz, N_latlong, N_rcu, N_rcu_inp, N_pn, S_pn, N_subbands, VALUES_PER_COMPLEX
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
-from tangostationcontrol.common.constants import N_elements, MAX_ANTENNA, N_pol, N_xyz, N_latlong, N_rcu, N_rcu_inp, N_pn, S_pn, N_subbands, VALUES_PER_COMPLEX
-from tangostationcontrol.common.cables import cable_types
-from tangostationcontrol.common.calibration import delay_compensation, loss_compensation
 from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES
-from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.common.type_checking import type_not_sequence
 from tangostationcontrol.devices.device_decorators import fault_on_error, only_in_states
+from tangostationcontrol.devices.lofar_device import LOFARDevice
 from tangostationcontrol.devices.sdp.common import subband_frequency, real_imag_to_weights
 from tangostationcontrol.devices.sdp.sdp import SDP
-from tangostationcontrol.beam.geo import ETRS_to_ITRF, ITRF_to_GEO, GEO_to_GEOHASH
-from tangostationcontrol.beam.hba_tile import HBATAntennaOffsets
 
 import logging
 
@@ -49,7 +52,7 @@ class AntennaQuality(IntEnum):
     BEYOND_REPAIR = 3
 
 
-class mapped_attribute(attribute):
+class MappedAttribute(attribute):
     def __init__(self, mapping_attribute, dtype, max_dim_x, max_dim_y=0, access=AttrWriteType.READ, **kwargs):
 
         if access == AttrWriteType.READ_WRITE:
@@ -73,7 +76,7 @@ class mapped_attribute(attribute):
 
 
 @device_logging_to_python()
-class AntennaField(lofar_device):
+class AntennaField(LOFARDevice):
     """ Manages the antennas in a single antenna field, by acting as a
         a mapping onto one or more RECV devices.
 
@@ -327,33 +330,59 @@ class AntennaField(lofar_device):
 
     # ----- Attributes mapped on RECV
 
-    ANT_mask_RW = mapped_attribute("ANT_mask_RW", dtype=(bool,), max_dim_x=MAX_ANTENNA,
-                                   access=AttrWriteType.READ_WRITE)
-    RCU_PWR_ANT_on_R = mapped_attribute("RCU_PWR_ANT_on_R", dtype=(bool,), max_dim_x=MAX_ANTENNA)
-    RCU_PWR_ANT_on_RW = mapped_attribute("RCU_PWR_ANT_on_RW", dtype=(bool,), max_dim_x=MAX_ANTENNA,
-                                         access=AttrWriteType.READ_WRITE)
-    HBAT_BF_delay_steps_R = mapped_attribute("HBAT_BF_delay_steps_R", dtype=((numpy.int64,),),
-                                             max_dim_x=N_elements * N_pol, max_dim_y=MAX_ANTENNA)
-    HBAT_BF_delay_steps_RW = mapped_attribute("HBAT_BF_delay_steps_RW", dtype=((numpy.int64,),),
-                                              max_dim_x=N_elements * N_pol, max_dim_y=MAX_ANTENNA,
-                                              access=AttrWriteType.READ_WRITE)
-    HBAT_LED_on_R = mapped_attribute("HBAT_LED_on_R", dtype=((bool,),), max_dim_x=N_elements * N_pol,
-                                     max_dim_y=MAX_ANTENNA)
-    HBAT_LED_on_RW = mapped_attribute("HBAT_LED_on_RW", dtype=((bool,),), max_dim_x=N_elements * N_pol,
-                                      max_dim_y=MAX_ANTENNA, access=AttrWriteType.READ_WRITE)
-    HBAT_PWR_LNA_on_R = mapped_attribute("HBAT_PWR_LNA_on_R", dtype=((bool,),),
-                                         max_dim_x=N_elements * N_pol, max_dim_y=MAX_ANTENNA)
-    HBAT_PWR_LNA_on_RW = mapped_attribute("HBAT_PWR_LNA_on_RW", dtype=((bool,),),
-                                          max_dim_x=N_elements * N_pol, max_dim_y=MAX_ANTENNA,
-                                          access=AttrWriteType.READ_WRITE)
-    HBAT_PWR_on_R = mapped_attribute("HBAT_PWR_on_R", dtype=((bool,),), max_dim_x=N_elements * N_pol,
-                                     max_dim_y=MAX_ANTENNA)
-    HBAT_PWR_on_RW = mapped_attribute("HBAT_PWR_on_RW", dtype=((bool,),), max_dim_x=N_elements * N_pol,
-                                      max_dim_y=MAX_ANTENNA, access=AttrWriteType.READ_WRITE)
-    RCU_band_select_RW = mapped_attribute("RCU_band_select_RW", dtype=(numpy.int64,), max_dim_x=MAX_ANTENNA,
-                                          access=AttrWriteType.READ_WRITE)
-    RCU_attenuator_dB_RW = mapped_attribute("RCU_attenuator_dB_RW", dtype=(numpy.int64,), max_dim_x=MAX_ANTENNA,
-                                            access=AttrWriteType.READ_WRITE)
+    ANT_mask_RW = MappedAttribute(
+        "ANT_mask_RW", dtype=(bool,), max_dim_x=MAX_ANTENNA,
+        access=AttrWriteType.READ_WRITE
+    )
+    RCU_PWR_ANT_on_R = MappedAttribute(
+        "RCU_PWR_ANT_on_R", dtype=(bool,), max_dim_x=MAX_ANTENNA
+    )
+    RCU_PWR_ANT_on_RW = MappedAttribute(
+        "RCU_PWR_ANT_on_RW", dtype=(bool,), max_dim_x=MAX_ANTENNA,
+        access=AttrWriteType.READ_WRITE
+    )
+    HBAT_BF_delay_steps_R = MappedAttribute(
+        "HBAT_BF_delay_steps_R", dtype=((numpy.int64,),),
+        max_dim_x=N_elements * N_pol, max_dim_y=MAX_ANTENNA
+    )
+    HBAT_BF_delay_steps_RW = MappedAttribute(
+        "HBAT_BF_delay_steps_RW", dtype=((numpy.int64,),),
+        max_dim_x=N_elements * N_pol, max_dim_y=MAX_ANTENNA,
+        access=AttrWriteType.READ_WRITE
+    )
+    HBAT_LED_on_R = MappedAttribute(
+        "HBAT_LED_on_R", dtype=((bool,),), max_dim_x=N_elements * N_pol,
+        max_dim_y=MAX_ANTENNA
+    )
+    HBAT_LED_on_RW = MappedAttribute(
+        "HBAT_LED_on_RW", dtype=((bool,),), max_dim_x=N_elements * N_pol,
+        max_dim_y=MAX_ANTENNA, access=AttrWriteType.READ_WRITE
+    )
+    HBAT_PWR_LNA_on_R = MappedAttribute(
+        "HBAT_PWR_LNA_on_R", dtype=((bool,),),
+        max_dim_x=N_elements * N_pol, max_dim_y=MAX_ANTENNA
+    )
+    HBAT_PWR_LNA_on_RW = MappedAttribute(
+        "HBAT_PWR_LNA_on_RW", dtype=((bool,),),
+        max_dim_x=N_elements * N_pol, max_dim_y=MAX_ANTENNA,
+        access=AttrWriteType.READ_WRITE
+    )
+    HBAT_PWR_on_R = MappedAttribute(
+        "HBAT_PWR_on_R", dtype=((bool,),), max_dim_x=N_elements * N_pol,
+        max_dim_y=MAX_ANTENNA
+    )
+    HBAT_PWR_on_RW = MappedAttribute(
+        "HBAT_PWR_on_RW", dtype=((bool,),), max_dim_x=N_elements * N_pol,
+        max_dim_y=MAX_ANTENNA, access=AttrWriteType.READ_WRITE
+    )
+    RCU_band_select_RW = MappedAttribute(
+        "RCU_band_select_RW", dtype=(numpy.int64,), max_dim_x=MAX_ANTENNA,
+        access=AttrWriteType.READ_WRITE
+    )
+    RCU_attenuator_dB_RW = MappedAttribute(
+        "RCU_attenuator_dB_RW", dtype=(numpy.int64,), max_dim_x=MAX_ANTENNA,
+        access=AttrWriteType.READ_WRITE
+    )
 
     # ----- Position information
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/apsct.py b/tangostationcontrol/tangostationcontrol/devices/apsct.py
index d39289c6f959cf92457d696a58fe021a5d3eda07..8cdd98c58bf77366d77841ca90a12d01c411e8b3 100644
--- a/tangostationcontrol/tangostationcontrol/devices/apsct.py
+++ b/tangostationcontrol/tangostationcontrol/devices/apsct.py
@@ -18,13 +18,13 @@ from tango import AttrWriteType
 import numpy
 # Additional import
 
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
 from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES
 from tangostationcontrol.common.constants import DEFAULT_POLLING_PERIOD
 from tangostationcontrol.devices.device_decorators import only_in_states
-from tangostationcontrol.devices.opcua_device import opcua_device
+from tangostationcontrol.devices.opcua_device import OPCUADevice
 
 import logging
 logger = logging.getLogger()
@@ -33,7 +33,7 @@ __all__ = ["APSCT", "main"]
 
 
 @device_logging_to_python()
-class APSCT(opcua_device):
+class APSCT(OPCUADevice):
     # -----------------
     # Device Properties
     # -----------------
@@ -61,31 +61,31 @@ class APSCT(opcua_device):
     # Attributes
     # ----------
 
-    APSCTTR_I2C_error_R          = attribute_wrapper(comms_annotation=["APSCTTR_I2C_error_R"       ],datatype=numpy.int64  )
-    APSCTTR_monitor_rate_RW      = attribute_wrapper(comms_annotation=["APSCTTR_monitor_rate_RW"   ],datatype=numpy.int64  , access=AttrWriteType.READ_WRITE)
-    APSCTTR_translator_busy_R    = attribute_wrapper(comms_annotation=["APSCTTR_translator_busy_R" ],datatype=bool)
-    APSCT_INPUT_10MHz_good_R     = attribute_wrapper(comms_annotation=["APSCT_INPUT_10MHz_good_R"  ],datatype=bool)
-    APSCT_INPUT_PPS_good_R       = attribute_wrapper(comms_annotation=["APSCT_INPUT_PPS_good_R"    ],datatype=bool)
-    APSCT_PCB_ID_R               = attribute_wrapper(comms_annotation=["APSCT_PCB_ID_R"            ],datatype=numpy.int64  )
-    APSCT_PCB_number_R           = attribute_wrapper(comms_annotation=["APSCT_PCB_number_R"        ],datatype=str          )
-    APSCT_PCB_version_R          = attribute_wrapper(comms_annotation=["APSCT_PCB_version_R"       ],datatype=str          )
-    APSCT_PLL_160MHz_error_R     = attribute_wrapper(comms_annotation=["APSCT_PLL_160MHz_error_R"  ],datatype=bool)
-    APSCT_PLL_160MHz_locked_R    = attribute_wrapper(comms_annotation=["APSCT_PLL_160MHz_locked_R" ],datatype=bool)
-    APSCT_PLL_200MHz_error_R     = attribute_wrapper(comms_annotation=["APSCT_PLL_200MHz_error_R"  ],datatype=bool)
-    APSCT_PLL_200MHz_locked_R    = attribute_wrapper(comms_annotation=["APSCT_PLL_200MHz_locked_R" ],datatype=bool)
-    APSCT_PPS_ignore_R           = attribute_wrapper(comms_annotation=["APSCT_PPS_ignore_R"        ],datatype=bool)
-    APSCT_PPS_ignore_RW          = attribute_wrapper(comms_annotation=["APSCT_PPS_ignore_RW"       ],datatype=bool, access=AttrWriteType.READ_WRITE)
-    APSCT_PWR_CLKDIST1_3V3_R     = attribute_wrapper(comms_annotation=["APSCT_PWR_CLKDIST1_3V3_R"  ],datatype=numpy.float64)
-    APSCT_PWR_CLKDIST2_3V3_R     = attribute_wrapper(comms_annotation=["APSCT_PWR_CLKDIST2_3V3_R"  ],datatype=numpy.float64)
-    APSCT_PWR_CTRL_3V3_R         = attribute_wrapper(comms_annotation=["APSCT_PWR_CTRL_3V3_R"      ],datatype=numpy.float64)
-    APSCT_PWR_INPUT_3V3_R        = attribute_wrapper(comms_annotation=["APSCT_PWR_INPUT_3V3_R"     ],datatype=numpy.float64)
-    APSCT_PWR_on_R               = attribute_wrapper(comms_annotation=["APSCT_PWR_on_R"            ],datatype=bool)
-    APSCT_PWR_PLL_160MHz_3V3_R   = attribute_wrapper(comms_annotation=["APSCT_PWR_PLL_160MHz_3V3_R"],datatype=numpy.float64)
-    APSCT_PWR_PLL_160MHz_on_R    = attribute_wrapper(comms_annotation=["APSCT_PWR_PLL_160MHz_on_R" ],datatype=bool)
-    APSCT_PWR_PLL_200MHz_3V3_R   = attribute_wrapper(comms_annotation=["APSCT_PWR_PLL_200MHz_3V3_R"],datatype=numpy.float64)
-    APSCT_PWR_PLL_200MHz_on_R    = attribute_wrapper(comms_annotation=["APSCT_PWR_PLL_200MHz_on_R" ],datatype=bool)
-    APSCT_PWR_PPSDIST_3V3_R      = attribute_wrapper(comms_annotation=["APSCT_PWR_PPSDIST_3V3_R"   ],datatype=numpy.float64)
-    APSCT_TEMP_R                 = attribute_wrapper(comms_annotation=["APSCT_TEMP_R"              ],datatype=numpy.float64)
+    APSCTTR_I2C_error_R          = AttributeWrapper(comms_annotation=["APSCTTR_I2C_error_R"       ],datatype=numpy.int64  )
+    APSCTTR_monitor_rate_RW      = AttributeWrapper(comms_annotation=["APSCTTR_monitor_rate_RW"   ],datatype=numpy.int64  , access=AttrWriteType.READ_WRITE)
+    APSCTTR_translator_busy_R    = AttributeWrapper(comms_annotation=["APSCTTR_translator_busy_R" ],datatype=bool)
+    APSCT_INPUT_10MHz_good_R     = AttributeWrapper(comms_annotation=["APSCT_INPUT_10MHz_good_R"  ],datatype=bool)
+    APSCT_INPUT_PPS_good_R       = AttributeWrapper(comms_annotation=["APSCT_INPUT_PPS_good_R"    ],datatype=bool)
+    APSCT_PCB_ID_R               = AttributeWrapper(comms_annotation=["APSCT_PCB_ID_R"            ],datatype=numpy.int64  )
+    APSCT_PCB_number_R           = AttributeWrapper(comms_annotation=["APSCT_PCB_number_R"        ],datatype=str          )
+    APSCT_PCB_version_R          = AttributeWrapper(comms_annotation=["APSCT_PCB_version_R"       ],datatype=str          )
+    APSCT_PLL_160MHz_error_R     = AttributeWrapper(comms_annotation=["APSCT_PLL_160MHz_error_R"  ],datatype=bool)
+    APSCT_PLL_160MHz_locked_R    = AttributeWrapper(comms_annotation=["APSCT_PLL_160MHz_locked_R" ],datatype=bool)
+    APSCT_PLL_200MHz_error_R     = AttributeWrapper(comms_annotation=["APSCT_PLL_200MHz_error_R"  ],datatype=bool)
+    APSCT_PLL_200MHz_locked_R    = AttributeWrapper(comms_annotation=["APSCT_PLL_200MHz_locked_R" ],datatype=bool)
+    APSCT_PPS_ignore_R           = AttributeWrapper(comms_annotation=["APSCT_PPS_ignore_R"        ],datatype=bool)
+    APSCT_PPS_ignore_RW          = AttributeWrapper(comms_annotation=["APSCT_PPS_ignore_RW"       ],datatype=bool, access=AttrWriteType.READ_WRITE)
+    APSCT_PWR_CLKDIST1_3V3_R     = AttributeWrapper(comms_annotation=["APSCT_PWR_CLKDIST1_3V3_R"  ],datatype=numpy.float64)
+    APSCT_PWR_CLKDIST2_3V3_R     = AttributeWrapper(comms_annotation=["APSCT_PWR_CLKDIST2_3V3_R"  ],datatype=numpy.float64)
+    APSCT_PWR_CTRL_3V3_R         = AttributeWrapper(comms_annotation=["APSCT_PWR_CTRL_3V3_R"      ],datatype=numpy.float64)
+    APSCT_PWR_INPUT_3V3_R        = AttributeWrapper(comms_annotation=["APSCT_PWR_INPUT_3V3_R"     ],datatype=numpy.float64)
+    APSCT_PWR_on_R               = AttributeWrapper(comms_annotation=["APSCT_PWR_on_R"            ],datatype=bool)
+    APSCT_PWR_PLL_160MHz_3V3_R   = AttributeWrapper(comms_annotation=["APSCT_PWR_PLL_160MHz_3V3_R"],datatype=numpy.float64)
+    APSCT_PWR_PLL_160MHz_on_R    = AttributeWrapper(comms_annotation=["APSCT_PWR_PLL_160MHz_on_R" ],datatype=bool)
+    APSCT_PWR_PLL_200MHz_3V3_R   = AttributeWrapper(comms_annotation=["APSCT_PWR_PLL_200MHz_3V3_R"],datatype=numpy.float64)
+    APSCT_PWR_PLL_200MHz_on_R    = AttributeWrapper(comms_annotation=["APSCT_PWR_PLL_200MHz_on_R" ],datatype=bool)
+    APSCT_PWR_PPSDIST_3V3_R      = AttributeWrapper(comms_annotation=["APSCT_PWR_PPSDIST_3V3_R"   ],datatype=numpy.float64)
+    APSCT_TEMP_R                 = AttributeWrapper(comms_annotation=["APSCT_TEMP_R"              ],datatype=numpy.float64)
 
     # ----------
     # Summarising Attributes
diff --git a/tangostationcontrol/tangostationcontrol/devices/apspu.py b/tangostationcontrol/tangostationcontrol/devices/apspu.py
index 08ee51fa8d968a3fcb5aed86809294a4471ed081..3b057c0b7408071cc68af9f82c94a9e8d143067c 100644
--- a/tangostationcontrol/tangostationcontrol/devices/apspu.py
+++ b/tangostationcontrol/tangostationcontrol/devices/apspu.py
@@ -18,8 +18,8 @@ import numpy
 # Additional import
 
 from tangostationcontrol.common.entrypoint import entry
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
-from tangostationcontrol.devices.opcua_device import opcua_device
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
+from tangostationcontrol.devices.opcua_device import OPCUADevice
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
 from tangostationcontrol.common.constants import DEFAULT_POLLING_PERIOD
 
@@ -27,7 +27,7 @@ __all__ = ["APSPU", "main"]
 
 
 @device_logging_to_python()
-class APSPU(opcua_device):
+class APSPU(OPCUADevice):
     # -----------------
     # Device Properties
     # -----------------
@@ -46,24 +46,24 @@ class APSPU(opcua_device):
     # Attributes
     # ----------
 
-    APSPUTR_I2C_error_R          = attribute_wrapper(comms_annotation=["APSPUTR_I2C_error_R"       ],datatype=numpy.int64  )
-    APSPUTR_monitor_rate_RW      = attribute_wrapper(comms_annotation=["APSPUTR_monitor_rate_RW"   ],datatype=numpy.int64  , access=AttrWriteType.READ_WRITE)
-    APSPUTR_translator_busy_R    = attribute_wrapper(comms_annotation=["APSPUTR_translator_busy_R" ],datatype=bool         )
-    APSPU_FAN1_RPM_R             = attribute_wrapper(comms_annotation=["APSPU_FAN1_RPM_R"          ],datatype=numpy.float64)
-    APSPU_FAN2_RPM_R             = attribute_wrapper(comms_annotation=["APSPU_FAN2_RPM_R"          ],datatype=numpy.float64)
-    APSPU_FAN3_RPM_R             = attribute_wrapper(comms_annotation=["APSPU_FAN3_RPM_R"          ],datatype=numpy.float64)
-    APSPU_LBA_IOUT_R             = attribute_wrapper(comms_annotation=["APSPU_LBA_IOUT_R"          ],datatype=numpy.float64)
-    APSPU_LBA_TEMP_R             = attribute_wrapper(comms_annotation=["APSPU_LBA_TEMP_R"          ],datatype=numpy.float64)
-    APSPU_LBA_VOUT_R             = attribute_wrapper(comms_annotation=["APSPU_LBA_VOUT_R"          ],datatype=numpy.float64)
-    APSPU_PCB_ID_R               = attribute_wrapper(comms_annotation=["APSPU_PCB_ID_R"            ],datatype=numpy.int64  )
-    APSPU_PCB_number_R           = attribute_wrapper(comms_annotation=["APSPU_PCB_number_R"        ],datatype=str          )
-    APSPU_PCB_version_R          = attribute_wrapper(comms_annotation=["APSPU_PCB_version_R"       ],datatype=str          )
-    APSPU_RCU2A_IOUT_R           = attribute_wrapper(comms_annotation=["APSPU_RCU2A_IOUT_R"        ],datatype=numpy.float64)
-    APSPU_RCU2A_TEMP_R           = attribute_wrapper(comms_annotation=["APSPU_RCU2A_TEMP_R"        ],datatype=numpy.float64)
-    APSPU_RCU2A_VOUT_R           = attribute_wrapper(comms_annotation=["APSPU_RCU2A_VOUT_R"        ],datatype=numpy.float64)
-    APSPU_RCU2D_IOUT_R           = attribute_wrapper(comms_annotation=["APSPU_RCU2D_IOUT_R"        ],datatype=numpy.float64)
-    APSPU_RCU2D_TEMP_R           = attribute_wrapper(comms_annotation=["APSPU_RCU2D_TEMP_R"        ],datatype=numpy.float64)
-    APSPU_RCU2D_VOUT_R           = attribute_wrapper(comms_annotation=["APSPU_RCU2D_VOUT_R"        ],datatype=numpy.float64)
+    APSPUTR_I2C_error_R          = AttributeWrapper(comms_annotation=["APSPUTR_I2C_error_R"       ],datatype=numpy.int64  )
+    APSPUTR_monitor_rate_RW      = AttributeWrapper(comms_annotation=["APSPUTR_monitor_rate_RW"   ],datatype=numpy.int64  , access=AttrWriteType.READ_WRITE)
+    APSPUTR_translator_busy_R    = AttributeWrapper(comms_annotation=["APSPUTR_translator_busy_R" ],datatype=bool         )
+    APSPU_FAN1_RPM_R             = AttributeWrapper(comms_annotation=["APSPU_FAN1_RPM_R"          ],datatype=numpy.float64)
+    APSPU_FAN2_RPM_R             = AttributeWrapper(comms_annotation=["APSPU_FAN2_RPM_R"          ],datatype=numpy.float64)
+    APSPU_FAN3_RPM_R             = AttributeWrapper(comms_annotation=["APSPU_FAN3_RPM_R"          ],datatype=numpy.float64)
+    APSPU_LBA_IOUT_R             = AttributeWrapper(comms_annotation=["APSPU_LBA_IOUT_R"          ],datatype=numpy.float64)
+    APSPU_LBA_TEMP_R             = AttributeWrapper(comms_annotation=["APSPU_LBA_TEMP_R"          ],datatype=numpy.float64)
+    APSPU_LBA_VOUT_R             = AttributeWrapper(comms_annotation=["APSPU_LBA_VOUT_R"          ],datatype=numpy.float64)
+    APSPU_PCB_ID_R               = AttributeWrapper(comms_annotation=["APSPU_PCB_ID_R"            ],datatype=numpy.int64  )
+    APSPU_PCB_number_R           = AttributeWrapper(comms_annotation=["APSPU_PCB_number_R"        ],datatype=str          )
+    APSPU_PCB_version_R          = AttributeWrapper(comms_annotation=["APSPU_PCB_version_R"       ],datatype=str          )
+    APSPU_RCU2A_IOUT_R           = AttributeWrapper(comms_annotation=["APSPU_RCU2A_IOUT_R"        ],datatype=numpy.float64)
+    APSPU_RCU2A_TEMP_R           = AttributeWrapper(comms_annotation=["APSPU_RCU2A_TEMP_R"        ],datatype=numpy.float64)
+    APSPU_RCU2A_VOUT_R           = AttributeWrapper(comms_annotation=["APSPU_RCU2A_VOUT_R"        ],datatype=numpy.float64)
+    APSPU_RCU2D_IOUT_R           = AttributeWrapper(comms_annotation=["APSPU_RCU2D_IOUT_R"        ],datatype=numpy.float64)
+    APSPU_RCU2D_TEMP_R           = AttributeWrapper(comms_annotation=["APSPU_RCU2D_TEMP_R"        ],datatype=numpy.float64)
+    APSPU_RCU2D_VOUT_R           = AttributeWrapper(comms_annotation=["APSPU_RCU2D_VOUT_R"        ],datatype=numpy.float64)
 
     # ----------
     # Summarising Attributes
diff --git a/tangostationcontrol/tangostationcontrol/devices/beam_device.py b/tangostationcontrol/tangostationcontrol/devices/beam_device.py
index 41e0b7f70cc1432e345f9420a058f5bafe0ab275..106647fbc340062f0cd0ed531fd952de70795821 100644
--- a/tangostationcontrol/tangostationcontrol/devices/beam_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/beam_device.py
@@ -26,15 +26,15 @@ from tangostationcontrol.common.lofar_logging import log_exceptions
 from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES
 from tangostationcontrol.devices.device_decorators import TimeIt, only_in_states, fault_on_error
 from tangostationcontrol.beam.delays import Delays
-from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.devices.lofar_device import LOFARDevice
 
-__all__ = ["beam_device", "main", "BeamTracker"]
+__all__ = ["BeamDevice", "main", "BeamTracker"]
 
 import logging
 logger = logging.getLogger()
 
 
-class beam_device(lofar_device):
+class BeamDevice(LOFARDevice):
     # -----------------
     # Device Properties
     # -----------------
@@ -359,7 +359,7 @@ class beam_device(lofar_device):
 # ----------
 def main(**kwargs):
     """Main function of the Docker module."""
-    return entry(beam_device, **kwargs)
+    return entry(BeamDevice, **kwargs)
 
 # ----------
 # Beam Tracker
diff --git a/tangostationcontrol/tangostationcontrol/devices/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py
index 7a411e728bac13cbec9adcbb0845b385b6a2520f..b6dcf838d2a2c0faf23d15d03b49b4d76767fe78 100644
--- a/tangostationcontrol/tangostationcontrol/devices/boot.py
+++ b/tangostationcontrol/tangostationcontrol/devices/boot.py
@@ -27,7 +27,7 @@ from tangostationcontrol.devices.device_decorators import only_in_states
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
 from tangostationcontrol.common.states import OPERATIONAL_STATES
-from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.devices.lofar_device import LOFARDevice
 
 import logging
 logger = logging.getLogger()
@@ -213,8 +213,7 @@ class DevicesInitialiser(object):
         self.set_status(f"[restarting {device_name}] Succesfully booted.")
 
 @device_logging_to_python()
-class Boot(lofar_device):
-
+class Boot(LOFARDevice):
     # maximum number of devices boot.py supports
     MAX_BOOT_DEVICES = 128
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/ccd.py b/tangostationcontrol/tangostationcontrol/devices/ccd.py
index ae95b6657ad96bbe8089062ba9aaf8df6c35a01d..20d1fd8042c06e8dd0b434c08648d9f13d94cded 100644
--- a/tangostationcontrol/tangostationcontrol/devices/ccd.py
+++ b/tangostationcontrol/tangostationcontrol/devices/ccd.py
@@ -18,13 +18,13 @@ from tango import AttrWriteType
 import numpy
 # Additional import
 
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
 from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES
 from tangostationcontrol.common.constants import DEFAULT_POLLING_PERIOD
 from tangostationcontrol.devices.device_decorators import only_in_states
-from tangostationcontrol.devices.opcua_device import opcua_device
+from tangostationcontrol.devices.opcua_device import OPCUADevice
 
 import logging
 logger = logging.getLogger()
@@ -33,7 +33,7 @@ __all__ = ["CCD", "main"]
 
 
 @device_logging_to_python()
-class CCD(opcua_device):
+class CCD(OPCUADevice):
     # -----------------
     # Device Properties
     # -----------------
@@ -56,28 +56,28 @@ class CCD(opcua_device):
     # ----------
     # Attributes
     # ----------
-    CCDTR_I2C_error_R =         attribute_wrapper(comms_annotation=["CCDTR_I2C_error_R"         ], datatype=numpy.int64)
-    CCDTR_monitor_rate_RW =     attribute_wrapper(comms_annotation=["CCDTR_monitor_rate_RW"     ], datatype=numpy.int64, access=AttrWriteType.READ_WRITE)
-    CCDTR_translator_busy_R =   attribute_wrapper(comms_annotation=["CCDTR_translator_busy_R"   ], datatype=bool)
-    CCD_clear_lock_R =          attribute_wrapper(comms_annotation=["CCD_clear_lock_R"          ], datatype=bool)
-    CCD_clear_lock_RW =         attribute_wrapper(comms_annotation=["CCD_clear_lock_RW"         ], datatype=bool, access=AttrWriteType.READ_WRITE)
-    CCD_FAN_RPM_R =             attribute_wrapper(comms_annotation=["CCD_FAN_RPM_R"             ], datatype=numpy.float64)
-    CCD_INPUT_10MHz_good_R =    attribute_wrapper(comms_annotation=["CCD_INPUT_10MHz_good_R"    ], datatype=bool)
-    CCD_INPUT_PPS_good_R =      attribute_wrapper(comms_annotation=["CCD_INPUT_PPS_good_R"      ], datatype=bool)
-    CCD_loss_lock_R =           attribute_wrapper(comms_annotation=["CCD_loss_lock_R"           ], datatype=bool)
-    CCD_PCB_ID_R =              attribute_wrapper(comms_annotation=["CCD_PCB_ID_R"              ], datatype=numpy.int64)
-    CCD_PCB_number_R =          attribute_wrapper(comms_annotation=["CCD_PCB_number_R"          ], datatype=str)
-    CCD_PCB_version_R =         attribute_wrapper(comms_annotation=["CCD_PCB_version_R"         ], datatype=str)
-    CCD_PLL_locked_R =          attribute_wrapper(comms_annotation=["CCD_PLL_locked_R"          ], datatype=bool)
-    CCD_PWR_CLK_DIST_3V3_R =    attribute_wrapper(comms_annotation=["CCD_PWR_CLK_DIST_3V3_R"    ], datatype=numpy.float64)
-    CCD_PWR_CLK_INPUT_3V3_R =   attribute_wrapper(comms_annotation=["CCD_PWR_CLK_INPUT_3V3_R"   ], datatype=numpy.float64)
-    CCD_PWR_CTRL_3V3_R =        attribute_wrapper(comms_annotation=["CCD_PWR_CTRL_3V3_R"        ], datatype=numpy.float64)
-    CCD_PWR_OCXO_INPUT_3V3_R =  attribute_wrapper(comms_annotation=["CCD_PWR_OCXO_INPUT_3V3_R"  ], datatype=numpy.float64)
-    CCD_PWR_on_R =              attribute_wrapper(comms_annotation=["CCD_PWR_on_R"              ], datatype=bool)
-    CCD_PWR_PLL_INPUT_3V3_R =   attribute_wrapper(comms_annotation=["CCD_PWR_PLL_INPUT_3V3_R"   ], datatype=numpy.float64)
-    CCD_PWR_PPS_INPUT_3V3_R =   attribute_wrapper(comms_annotation=["CCD_PWR_PPS_INPUT_3V3_R"   ], datatype=numpy.float64)
-    CCD_PWR_PPS_OUTPUT_3V3_R =  attribute_wrapper(comms_annotation=["CCD_PWR_PPS_OUTPUT_3V3_R"  ], datatype=numpy.float64)
-    CCD_TEMP_R =                attribute_wrapper(comms_annotation=["CCD_TEMP_R"                ], datatype=numpy.float64)
+    CCDTR_I2C_error_R =         AttributeWrapper(comms_annotation=["CCDTR_I2C_error_R"         ], datatype=numpy.int64)
+    CCDTR_monitor_rate_RW =     AttributeWrapper(comms_annotation=["CCDTR_monitor_rate_RW"     ], datatype=numpy.int64, access=AttrWriteType.READ_WRITE)
+    CCDTR_translator_busy_R =   AttributeWrapper(comms_annotation=["CCDTR_translator_busy_R"   ], datatype=bool)
+    CCD_clear_lock_R =          AttributeWrapper(comms_annotation=["CCD_clear_lock_R"          ], datatype=bool)
+    CCD_clear_lock_RW =         AttributeWrapper(comms_annotation=["CCD_clear_lock_RW"         ], datatype=bool, access=AttrWriteType.READ_WRITE)
+    CCD_FAN_RPM_R =             AttributeWrapper(comms_annotation=["CCD_FAN_RPM_R"             ], datatype=numpy.float64)
+    CCD_INPUT_10MHz_good_R =    AttributeWrapper(comms_annotation=["CCD_INPUT_10MHz_good_R"    ], datatype=bool)
+    CCD_INPUT_PPS_good_R =      AttributeWrapper(comms_annotation=["CCD_INPUT_PPS_good_R"      ], datatype=bool)
+    CCD_loss_lock_R =           AttributeWrapper(comms_annotation=["CCD_loss_lock_R"           ], datatype=bool)
+    CCD_PCB_ID_R =              AttributeWrapper(comms_annotation=["CCD_PCB_ID_R"              ], datatype=numpy.int64)
+    CCD_PCB_number_R =          AttributeWrapper(comms_annotation=["CCD_PCB_number_R"          ], datatype=str)
+    CCD_PCB_version_R =         AttributeWrapper(comms_annotation=["CCD_PCB_version_R"         ], datatype=str)
+    CCD_PLL_locked_R =          AttributeWrapper(comms_annotation=["CCD_PLL_locked_R"          ], datatype=bool)
+    CCD_PWR_CLK_DIST_3V3_R =    AttributeWrapper(comms_annotation=["CCD_PWR_CLK_DIST_3V3_R"    ], datatype=numpy.float64)
+    CCD_PWR_CLK_INPUT_3V3_R =   AttributeWrapper(comms_annotation=["CCD_PWR_CLK_INPUT_3V3_R"   ], datatype=numpy.float64)
+    CCD_PWR_CTRL_3V3_R =        AttributeWrapper(comms_annotation=["CCD_PWR_CTRL_3V3_R"        ], datatype=numpy.float64)
+    CCD_PWR_OCXO_INPUT_3V3_R =  AttributeWrapper(comms_annotation=["CCD_PWR_OCXO_INPUT_3V3_R"  ], datatype=numpy.float64)
+    CCD_PWR_on_R =              AttributeWrapper(comms_annotation=["CCD_PWR_on_R"              ], datatype=bool)
+    CCD_PWR_PLL_INPUT_3V3_R =   AttributeWrapper(comms_annotation=["CCD_PWR_PLL_INPUT_3V3_R"   ], datatype=numpy.float64)
+    CCD_PWR_PPS_INPUT_3V3_R =   AttributeWrapper(comms_annotation=["CCD_PWR_PPS_INPUT_3V3_R"   ], datatype=numpy.float64)
+    CCD_PWR_PPS_OUTPUT_3V3_R =  AttributeWrapper(comms_annotation=["CCD_PWR_PPS_OUTPUT_3V3_R"  ], datatype=numpy.float64)
+    CCD_TEMP_R =                AttributeWrapper(comms_annotation=["CCD_TEMP_R"                ], datatype=numpy.float64)
     # ----------
     # Summarising Attributes
     # ----------
diff --git a/tangostationcontrol/tangostationcontrol/devices/configuration_device.py b/tangostationcontrol/tangostationcontrol/devices/configuration_device.py
index ad6e63c32c6f2325565c2e026ab5577b50ac5897..ee75edef6aa55695f7cb971942d5fcd8e3fe70b7 100644
--- a/tangostationcontrol/tangostationcontrol/devices/configuration_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/configuration_device.py
@@ -19,7 +19,7 @@ from tango.server import attribute
 # Additional import
 from tangostationcontrol.common.configuration import StationConfiguration
 from tangostationcontrol.common.entrypoint import entry
-from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.devices.lofar_device import LOFARDevice
 from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
 
 import json
@@ -29,7 +29,7 @@ logger = logging.getLogger()
 __all__ = ["Configuration", "main"]
 
 @device_logging_to_python()
-class Configuration(lofar_device):
+class Configuration(LOFARDevice):
     # -----------------
     # Device Properties
     # -----------------
diff --git a/tangostationcontrol/tangostationcontrol/devices/docker_device.py b/tangostationcontrol/tangostationcontrol/devices/docker_device.py
index 5336354d8ad9c5ed0c4776b6c5c254ec4d3a41c8..b37072c915961e10632a7c65dc02ffc863b76fe7 100644
--- a/tangostationcontrol/tangostationcontrol/devices/docker_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/docker_device.py
@@ -19,8 +19,8 @@ import asyncio
 # Additional import
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.clients.docker_client import DockerClient
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
-from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
+from tangostationcontrol.devices.lofar_device import LOFARDevice
 from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
 
 import logging
@@ -28,8 +28,9 @@ logger = logging.getLogger()
 
 __all__ = ["Docker", "main"]
 
+
 @device_logging_to_python()
-class Docker(lofar_device):
+class Docker(LOFARDevice):
     # -----------------
     # Device Properties
     # -----------------
@@ -45,86 +46,86 @@ class Docker(lofar_device):
     # ----------
 
     # 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_configuration_R = attribute_wrapper(comms_annotation={"container": "device-configuration"}, datatype=bool)
-    device_configuration_RW = attribute_wrapper(comms_annotation={"container": "device-configuration"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_boot_R = AttributeWrapper(comms_annotation={"container": "device-boot"}, datatype=bool)
+    device_boot_RW = AttributeWrapper(comms_annotation={"container": "device-boot"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_docker_R = AttributeWrapper(comms_annotation={"container": "device-docker"}, datatype=bool)
+    device_configuration_R = AttributeWrapper(comms_annotation={"container": "device-configuration"}, datatype=bool)
+    device_configuration_RW = AttributeWrapper(comms_annotation={"container": "device-configuration"}, datatype=bool, access=AttrWriteType.READ_WRITE)
     # 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)
+    device_temperature_manager_R = AttributeWrapper(comms_annotation={"container": "device-temperature-manager"}, datatype=bool)
+    device_temperature_manager_RW = AttributeWrapper(comms_annotation={"container": "device-temperature-manager"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_observation_R = AttributeWrapper(comms_annotation={"container": "device-observation"}, datatype=bool)
+    device_observation_RW = AttributeWrapper(comms_annotation={"container": "device-observation"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_observation_control_R = AttributeWrapper(comms_annotation={"container": "device-observation-control"}, datatype=bool)
+    device_observation_control_RW = AttributeWrapper(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_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)
+    device_apsct_R = AttributeWrapper(comms_annotation={"container": "device-apsct"}, datatype=bool)
+    device_apsct_RW = AttributeWrapper(comms_annotation={"container": "device-apsct"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_apspu_R = AttributeWrapper(comms_annotation={"container": "device-apspu"}, datatype=bool)
+    device_apspu_RW = AttributeWrapper(comms_annotation={"container": "device-apspu"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_recv_R = AttributeWrapper(comms_annotation={"container": "device-recv"}, datatype=bool)
+    device_recv_RW = AttributeWrapper(comms_annotation={"container": "device-recv"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_sdp_R = AttributeWrapper(comms_annotation={"container": "device-sdp"}, datatype=bool)
+    device_sdp_RW = AttributeWrapper(comms_annotation={"container": "device-sdp"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_unb2_R = AttributeWrapper(comms_annotation={"container": "device-unb2"}, datatype=bool)
+    device_unb2_RW = AttributeWrapper(comms_annotation={"container": "device-unb2"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_pcon_R = AttributeWrapper(comms_annotation={"container": "device-pcon"}, datatype=bool)
+    device_pcon_RW = AttributeWrapper(comms_annotation={"container": "device-pcon"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_psoc_R = AttributeWrapper(comms_annotation={"container": "device-psoc"}, datatype=bool)
+    device_psoc_RW = AttributeWrapper(comms_annotation={"container": "device-psoc"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_ccd_R = AttributeWrapper(comms_annotation={"container": "device-ccd"}, datatype=bool)
+    device_ccd_RW = AttributeWrapper(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_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)
+    device_sst_R = AttributeWrapper(comms_annotation={"container": "device-sst"}, datatype=bool)
+    device_sst_RW = AttributeWrapper(comms_annotation={"container": "device-sst"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_xst_R = AttributeWrapper(comms_annotation={"container": "device-xst"}, datatype=bool)
+    device_xst_RW = AttributeWrapper(comms_annotation={"container": "device-xst"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_bst_R = AttributeWrapper(comms_annotation={"container": "device-bst"}, datatype=bool)
+    device_bst_RW = AttributeWrapper(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)
+    device_antennafield_R = AttributeWrapper(comms_annotation={"container": "device-antennafield"}, datatype=bool)
+    device_antennafield_RW = AttributeWrapper(comms_annotation={"container": "device-antennafield"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_beamlet_R = AttributeWrapper(comms_annotation={"container": "device-beamlet"}, datatype=bool)
+    device_beamlet_RW = AttributeWrapper(comms_annotation={"container": "device-beamlet"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_digitalbeam_R = AttributeWrapper(comms_annotation={"container": "device-digitalbeam"}, datatype=bool)
+    device_digitalbeam_RW = AttributeWrapper(comms_annotation={"container": "device-digitalbeam"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    device_tilebeam_R = AttributeWrapper(comms_annotation={"container": "device-tilebeam"}, datatype=bool)
+    device_tilebeam_RW = AttributeWrapper(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)
-    grafana_R = attribute_wrapper(comms_annotation={"container": "grafana"}, datatype=bool)
-    grafana_RW = attribute_wrapper(comms_annotation={"container": "grafana"}, datatype=bool, access=AttrWriteType.READ_WRITE)
-    logstash_R = attribute_wrapper(comms_annotation={"container": "logstash"}, datatype=bool)
-    logstash_RW = attribute_wrapper(comms_annotation={"container": "logstash"}, datatype=bool, access=AttrWriteType.READ_WRITE)
-    loki_R = attribute_wrapper(comms_annotation={"container": "loki"}, datatype=bool)
-    loki_RW = attribute_wrapper(comms_annotation={"container": "loki"}, datatype=bool, access=AttrWriteType.READ_WRITE)
-    hdbppts_cm_R = attribute_wrapper(comms_annotation={"container": "hdbppts-cm"}, datatype=bool)
-    hdbppts_cm_RW = attribute_wrapper(comms_annotation={"container": "hdbppts-cm"}, datatype=bool, access=AttrWriteType.READ_WRITE)
-    hdbppts_es_R = attribute_wrapper(comms_annotation={"container": "hdbppts-es"}, datatype=bool)
-    hdbppts_es_RW = attribute_wrapper(comms_annotation={"container": "hdbppts-es"}, datatype=bool, access=AttrWriteType.READ_WRITE)
-    itango_R = attribute_wrapper(comms_annotation={"container": "itango"}, datatype=bool)
-    itango_RW = attribute_wrapper(comms_annotation={"container": "itango"}, datatype=bool, access=AttrWriteType.READ_WRITE)
-    jupyter_lab_R = attribute_wrapper(comms_annotation={"container": "jupyter-lab"}, datatype=bool)
-    jupyter_lab_RW = attribute_wrapper(comms_annotation={"container": "jupyter-lab"}, 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)
+    archiver_timescale_R = AttributeWrapper(comms_annotation={"container": "archiver-timescale"}, datatype=bool)
+    archiver_timescale_RW = AttributeWrapper(comms_annotation={"container": "archiver-timescale"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    databaseds_R = AttributeWrapper(comms_annotation={"container": "databaseds"}, datatype=bool)
+    databaseds_RW = AttributeWrapper(comms_annotation={"container": "databaseds"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    dsconfig_R = AttributeWrapper(comms_annotation={"container": "dsconfig"}, datatype=bool)
+    dsconfig_RW = AttributeWrapper(comms_annotation={"container": "dsconfig"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    grafana_R = AttributeWrapper(comms_annotation={"container": "grafana"}, datatype=bool)
+    grafana_RW = AttributeWrapper(comms_annotation={"container": "grafana"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    logstash_R = AttributeWrapper(comms_annotation={"container": "logstash"}, datatype=bool)
+    logstash_RW = AttributeWrapper(comms_annotation={"container": "logstash"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    loki_R = AttributeWrapper(comms_annotation={"container": "loki"}, datatype=bool)
+    loki_RW = AttributeWrapper(comms_annotation={"container": "loki"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    hdbppts_cm_R = AttributeWrapper(comms_annotation={"container": "hdbppts-cm"}, datatype=bool)
+    hdbppts_cm_RW = AttributeWrapper(comms_annotation={"container": "hdbppts-cm"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    hdbppts_es_R = AttributeWrapper(comms_annotation={"container": "hdbppts-es"}, datatype=bool)
+    hdbppts_es_RW = AttributeWrapper(comms_annotation={"container": "hdbppts-es"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    itango_R = AttributeWrapper(comms_annotation={"container": "itango"}, datatype=bool)
+    itango_RW = AttributeWrapper(comms_annotation={"container": "itango"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    jupyter_lab_R = AttributeWrapper(comms_annotation={"container": "jupyter-lab"}, datatype=bool)
+    jupyter_lab_RW = AttributeWrapper(comms_annotation={"container": "jupyter-lab"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    tangodb_R = AttributeWrapper(comms_annotation={"container": "tangodb"}, datatype=bool)
+    tangodb_RW = AttributeWrapper(comms_annotation={"container": "tangodb"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    prometheus_R = AttributeWrapper(comms_annotation={"container": "prometheus"}, datatype=bool)
+    prometheus_RW = AttributeWrapper(comms_annotation={"container": "prometheus"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    tango_prometheus_exporter_R = AttributeWrapper(comms_annotation={"container": "tango-prometheus-exporter"}, datatype=bool)
+    tango_prometheus_exporter_RW = AttributeWrapper(comms_annotation={"container": "tango-prometheus-exporter"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    prometheus_node_exporter_R = AttributeWrapper(comms_annotation={"container": "prometheus-node-exporter"}, datatype=bool)
+    prometheus_node_exporter_RW = AttributeWrapper(comms_annotation={"container": "prometheus-node-exporter"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    tango_rest_R = AttributeWrapper(comms_annotation={"container": "tango-rest"}, datatype=bool)
+    tango_rest_RW = AttributeWrapper(comms_annotation={"container": "tango-rest"}, datatype=bool, access=AttrWriteType.READ_WRITE)
 
     # --------
     # overloaded functions
diff --git a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
index 662c3303289549f74495d1179a718bcdaa7ab939..def3d167b1016680b4e36051377cf04977df0b53 100644
--- a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
@@ -23,8 +23,7 @@ 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.clients.attribute_wrapper import AttributeWrapper
 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
@@ -32,13 +31,13 @@ from tangostationcontrol.devices.device_decorators import only_in_states, fault_
 from tangostationcontrol.toolkit.archiver import Archiver
 
 
-__all__ = ["lofar_device"]
+__all__ = ["LOFARDevice"]
 
 import logging
 logger = logging.getLogger()
 
 
-class lofar_device(Device, metaclass=DeviceMeta):
+class LOFARDevice(Device, metaclass=DeviceMeta):
     """
 
     **Properties:**
@@ -83,8 +82,8 @@ class lofar_device(Device, metaclass=DeviceMeta):
 
     @classmethod
     def attr_list(cls):
-        """ Return a list of all the attribute_wrapper members of this class. """
-        return [v for k, v in cls.__dict__.items() if type(v) == attribute_wrapper]
+        """ Return a list of all the AttributeWrapper members of this class. """
+        return [v for k, v in cls.__dict__.items() if type(v) == AttributeWrapper]
 
     def setup_attribute_wrapper(self):
         """ prepare the caches for attribute wrapper objects"""
@@ -92,7 +91,7 @@ class lofar_device(Device, metaclass=DeviceMeta):
         self._attribute_wrapper_io = {}
 
     def is_attribute_access_allowed(self, req_type):
-        """ Returns whether an attribute wrapped by the attribute_wrapper be accessed. """
+        """ Returns whether an attribute wrapped by the AttributeWrapper be accessed. """
 
         return self.get_state() in INITIALISED_STATES
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/observation.py b/tangostationcontrol/tangostationcontrol/devices/observation.py
index f4746628e125bbd913cef63b191d09fd78594249..dc129014c3f3a4c20ad1e68e5ddcdb7dec555880 100644
--- a/tangostationcontrol/tangostationcontrol/devices/observation.py
+++ b/tangostationcontrol/tangostationcontrol/devices/observation.py
@@ -10,6 +10,7 @@ from typing import Optional
 
 import numpy
 from jsonschema.exceptions import ValidationError
+
 # PyTango imports
 from tango import AttrWriteType, DeviceProxy, DevState, DevSource, Util, Except
 from tango.server import attribute
@@ -22,7 +23,7 @@ from tangostationcontrol.configuration import ObservationSettings
 from tangostationcontrol.devices.device_decorators import fault_on_error
 from tangostationcontrol.devices.device_decorators import only_in_states
 from tangostationcontrol.devices.device_decorators import only_when_on
-from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.devices.lofar_device import LOFARDevice
 
 logger = logging.getLogger()
 
@@ -30,7 +31,7 @@ __all__ = ["Observation", "main"]
 
 
 @device_logging_to_python()
-class Observation(lofar_device):
+class Observation(LOFARDevice):
     """ Observation Device for LOFAR2.0
     This Tango device is responsible for the set-up of hardware for a
     specific observation.  It will, if necessary keep tabs on HW MPs to signal
diff --git a/tangostationcontrol/tangostationcontrol/devices/observation_control.py b/tangostationcontrol/tangostationcontrol/devices/observation_control.py
index f02571f865a58af39cea33e02df940e9fceec9eb..d241dcbe634c233995ea8d6cf7613ac1bb406479 100644
--- a/tangostationcontrol/tangostationcontrol/devices/observation_control.py
+++ b/tangostationcontrol/tangostationcontrol/devices/observation_control.py
@@ -16,7 +16,7 @@ from tangostationcontrol.common.lofar_logging import device_logging_to_python, l
 from tangostationcontrol.common import ObservationController
 from tangostationcontrol.configuration import ObservationSettings
 from tangostationcontrol.devices.device_decorators import only_when_on, fault_on_error
-from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.devices.lofar_device import LOFARDevice
 from tangostationcontrol.devices.observation import Observation
 
 logger = logging.getLogger()
@@ -25,7 +25,7 @@ __all__ = ["ObservationControl", "main"]
 
 
 @device_logging_to_python()
-class ObservationControl(lofar_device):
+class ObservationControl(LOFARDevice):
     """ Observation Control Device Server for LOFAR2.0
     The ObservationControl Tango device controls the instantiation of a Tango Dynamic Device from the Observation class.
     ObservationControl then keeps a record of the Observation devices and if they are still alive.
diff --git a/tangostationcontrol/tangostationcontrol/devices/opcua_device.py b/tangostationcontrol/tangostationcontrol/devices/opcua_device.py
index c5fa4d1a791bc2511ae93f9e30091c0c1beba2c8..23624f9078b85f1a0f464251751abb6d7044f7bb 100644
--- a/tangostationcontrol/tangostationcontrol/devices/opcua_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/opcua_device.py
@@ -19,15 +19,15 @@ import asyncio
 
 from tangostationcontrol.common.lofar_logging import log_exceptions
 from tangostationcontrol.clients.opcua_client import OPCUAConnection
-from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.devices.lofar_device import LOFARDevice
 
 import logging
 logger = logging.getLogger()
 
-__all__ = ["opcua_device"]
+__all__ = ["OPCUADevice"]
 
 
-class opcua_device(lofar_device):
+class OPCUADevice(LOFARDevice):
     """
 
     **Properties:**
diff --git a/tangostationcontrol/tangostationcontrol/devices/pcon.py b/tangostationcontrol/tangostationcontrol/devices/pcon.py
index 02bf7d9d70f33a5ac6a52ca4fa966fa9b20cde42..fe7ceb280816db1d996e3e0c1acbeb2b4865e729 100644
--- a/tangostationcontrol/tangostationcontrol/devices/pcon.py
+++ b/tangostationcontrol/tangostationcontrol/devices/pcon.py
@@ -12,8 +12,8 @@ from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
 
 import logging
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
-from tangostationcontrol.devices.snmp_device import snmp_device
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
+from tangostationcontrol.devices.snmp_device import SNMPDevice
 
 import numpy
 
@@ -27,18 +27,18 @@ __all__ = ["PCON", "main"]
 
 
 @device_logging_to_python()
-class PCON(snmp_device):
+class PCON(SNMPDevice):
 
     # ----------
     # Attributes
     # ----------
-    systemVoltage_R = attribute_wrapper(comms_annotation={"mib": "ACC-MIB", "name": "systemVoltage", "scaling_factor": 0.01}, datatype=numpy.double)
+    systemVoltage_R = AttributeWrapper(comms_annotation={"mib": "ACC-MIB", "name": "systemVoltage", "scaling_factor": 0.01}, datatype=numpy.double)
 
-    rectifierCurrent_R = attribute_wrapper(comms_annotation={"mib": "ACC-MIB", "name": "rectifierCurrent", "scaling_factor": 0.1}, datatype=numpy.double)
-    loadCurrent_R = attribute_wrapper(comms_annotation={"mib": "ACC-MIB", "name": "loadCurrent", "scaling_factor": 0.1}, datatype=numpy.double)
-    batteryCurrent_R = attribute_wrapper(comms_annotation={"mib": "ACC-MIB", "name": "batteryCurrent", "scaling_factor": 0.1}, datatype=numpy.double)
+    rectifierCurrent_R = AttributeWrapper(comms_annotation={"mib": "ACC-MIB", "name": "rectifierCurrent", "scaling_factor": 0.1}, datatype=numpy.double)
+    loadCurrent_R = AttributeWrapper(comms_annotation={"mib": "ACC-MIB", "name": "loadCurrent", "scaling_factor": 0.1}, datatype=numpy.double)
+    batteryCurrent_R = AttributeWrapper(comms_annotation={"mib": "ACC-MIB", "name": "batteryCurrent", "scaling_factor": 0.1}, datatype=numpy.double)
 
-    battTemperature_R = attribute_wrapper(comms_annotation={"mib": "ACC-MIB", "name": "battTemperature"}, datatype=numpy.double)
+    battTemperature_R = AttributeWrapper(comms_annotation={"mib": "ACC-MIB", "name": "battTemperature"}, datatype=numpy.double)
 
 
 # ----------
diff --git a/tangostationcontrol/tangostationcontrol/devices/psoc.py b/tangostationcontrol/tangostationcontrol/devices/psoc.py
index 31e1393cec0c5ab09633fa8566fc8deef956b13a..425faa23a87b7ebbc209e392e77b1b10a3844ef7 100644
--- a/tangostationcontrol/tangostationcontrol/devices/psoc.py
+++ b/tangostationcontrol/tangostationcontrol/devices/psoc.py
@@ -14,9 +14,9 @@ from tangostationcontrol.common.lofar_logging import device_logging_to_python, l
 from tango.server import device_property, command
 
 import logging
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
-from tangostationcontrol.clients.snmp_client import snmp_attribute
-from tangostationcontrol.devices.snmp_device import snmp_device
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
+from tangostationcontrol.clients.snmp_client import SNMPAttribute
+from tangostationcontrol.devices.snmp_device import SNMPDevice
 
 import numpy
 from datetime import timedelta
@@ -31,8 +31,7 @@ __all__ = ["PSOC", "main"]
 
 
 @device_logging_to_python()
-class PSOC(snmp_device):
-
+class PSOC(SNMPDevice):
     # number of sockets the psoc has
     PSOC_SOCKETS = 8
 
@@ -47,10 +46,10 @@ class PSOC(snmp_device):
     # ----------
     # Attributes
     # ----------
-    sockets_state_R = attribute_wrapper(comms_annotation={"mib": "PowerNet-MIB", "name": "sPDUOutletCtl", "index": 1}, dims=(PSOC_SOCKETS,), datatype=str)
-    master_state_R = attribute_wrapper(comms_annotation={"mib": "PowerNet-MIB", "name": "sPDUMasterState"}, datatype=str)
-    current_load_R = attribute_wrapper(comms_annotation={"mib": "PowerNet-MIB", "name": "rPDULoadStatusLoad", "index": 1}, datatype=numpy.int64)
-    uptime_R = attribute_wrapper(comms_annotation={"mib": "SNMPv2-MIB", "name": "sysUpTime"}, datatype=numpy.int64)
+    sockets_state_R = AttributeWrapper(comms_annotation={"mib": "PowerNet-MIB", "name": "sPDUOutletCtl", "index": 1}, dims=(8,), datatype=str)
+    master_state_R = AttributeWrapper(comms_annotation={"mib": "PowerNet-MIB", "name": "sPDUMasterState"}, datatype=str)
+    current_load_R = AttributeWrapper(comms_annotation={"mib": "PowerNet-MIB", "name": "rPDULoadStatusLoad", "index": 1}, datatype=numpy.int64)
+    uptime_R = AttributeWrapper(comms_annotation={"mib": "SNMPv2-MIB", "name": "sysUpTime"}, datatype=numpy.int64)
 
     # --------
     # overloaded functions
@@ -72,7 +71,7 @@ class PSOC(snmp_device):
         super().configure_for_initialise()
 
         # prepares this object for the readable_uptime command
-        self.uptime_attr = snmp_attribute(self.snmp_manager.SNMP_comm, "SNMPv2-MIB", name="sysUpTime", idx=0, dtype=numpy.int64, dim_x=1, dim_y=0)
+        self.uptime_attr = SNMPAttribute(self.snmp_manager.SNMP_comm, "SNMPv2-MIB", name="sysUpTime", idx=0, dtype=numpy.int64, dim_x=1, dim_y=0)
 
     def _toggle_socket(self, socket_name, on: bool):
         """
@@ -90,8 +89,8 @@ class PSOC(snmp_device):
         else:
             socket_set = "outletOff"
 
-        # create the snmp_attribute for the correct socket
-        attr = snmp_attribute(self.snmp_manager.SNMP_comm, "PowerNet-MIB", name="sPDUOutletCtl", idx=socket_nr, dtype=str, dim_x=1, dim_y=0)
+        # create the SNMPAttribute for the correct socket
+        attr = SNMPAttribute(self.snmp_manager.SNMP_comm, "PowerNet-MIB", name="sPDUOutletCtl", idx=socket_nr, dtype=str, dim_x=1, dim_y=0)
 
         # write the correct value
         attr.write_function([socket_set])
diff --git a/tangostationcontrol/tangostationcontrol/devices/recv.py b/tangostationcontrol/tangostationcontrol/devices/recv.py
index e53fcbd4035b433019aacc45197f94bb1ef1f293..6325e2ac6c81efd0c45078a4be779250c274753d 100644
--- a/tangostationcontrol/tangostationcontrol/devices/recv.py
+++ b/tangostationcontrol/tangostationcontrol/devices/recv.py
@@ -24,9 +24,9 @@ from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
 from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES
 from tangostationcontrol.common.constants import N_rcu, N_elements, N_pol, N_rcu_inp, DEFAULT_POLLING_PERIOD
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
 from tangostationcontrol.devices.device_decorators import only_in_states
-from tangostationcontrol.devices.opcua_device import opcua_device
+from tangostationcontrol.devices.opcua_device import OPCUADevice
 
 import logging
 
@@ -36,7 +36,7 @@ __all__ = ["RECV", "main"]
 
 
 @device_logging_to_python()
-class RECV(opcua_device):
+class RECV(OPCUADevice):
 
     FILTER_RCU_DICT = {
         "LBA_10_90": 1,
@@ -139,67 +139,121 @@ class RECV(opcua_device):
     # ----------
     # Attributes
     # ----------
-
-    ANT_mask_RW = attribute_wrapper(comms_annotation=["ANT_mask_RW"], datatype=bool, dims=(N_rcu * N_rcu_inp,),
-                                    access=AttrWriteType.READ_WRITE)
+    ANT_mask_RW = AttributeWrapper(
+        comms_annotation=["ANT_mask_RW"], datatype=bool, dims=(N_rcu * N_rcu_inp,),
+        access=AttrWriteType.READ_WRITE
+    )
 
     # The HBAT beamformer delays represent 32 delays for each of the 96 inputs.
-    # The 32 delays deconstruct as delays[polarisation][dipole], and each delay is the number of 'delay steps' to apply (0.5ns for HBAT1).
-    HBAT_BF_delay_steps_R = attribute_wrapper(comms_annotation=["HBAT_BF_delay_steps_R"], datatype=numpy.int64,
-                                              dims=(N_rcu * N_rcu_inp, N_elements, N_pol))
-    HBAT_BF_delay_steps_RW = attribute_wrapper(comms_annotation=["HBAT_BF_delay_steps_RW"], datatype=numpy.int64,
-                                               dims=(N_rcu * N_rcu_inp, N_elements, N_pol), access=AttrWriteType.READ_WRITE)
-    HBAT_LED_on_R = attribute_wrapper(comms_annotation=["HBAT_LED_on_R"], datatype=bool, dims=(N_rcu * N_rcu_inp, N_elements, N_pol))
-    HBAT_LED_on_RW = attribute_wrapper(comms_annotation=["HBAT_LED_on_RW"], datatype=bool, dims=(N_rcu * N_rcu_inp, N_elements, N_pol),
-                                       access=AttrWriteType.READ_WRITE)
-    HBAT_PWR_LNA_on_R = attribute_wrapper(comms_annotation=["HBAT_PWR_LNA_on_R"], datatype=bool, dims=(N_rcu * N_rcu_inp, N_elements, N_pol))
-    HBAT_PWR_LNA_on_RW = attribute_wrapper(comms_annotation=["HBAT_PWR_LNA_on_RW"], datatype=bool, dims=(N_rcu * N_rcu_inp, N_elements, N_pol),
-                                           access=AttrWriteType.READ_WRITE)
-    HBAT_PWR_on_R = attribute_wrapper(comms_annotation=["HBAT_PWR_on_R"], datatype=bool, dims=(N_rcu * N_rcu_inp, N_elements, N_pol))
-    HBAT_PWR_on_RW = attribute_wrapper(comms_annotation=["HBAT_PWR_on_RW"], datatype=bool, dims=(N_rcu * N_rcu_inp, N_elements, N_pol),
-                                       access=AttrWriteType.READ_WRITE)
-    RCU_ADC_locked_R = attribute_wrapper(comms_annotation=["RCU_ADC_locked_R"], datatype=bool, dims=(N_rcu, N_rcu_inp))
-    RCU_attenuator_dB_R = attribute_wrapper(comms_annotation=["RCU_attenuator_dB_R"], datatype=numpy.int64,
-                                            dims=(N_rcu, N_rcu_inp))
-    RCU_attenuator_dB_RW = attribute_wrapper(comms_annotation=["RCU_attenuator_dB_RW"], datatype=numpy.int64,
-                                             dims=(N_rcu, N_rcu_inp), access=AttrWriteType.READ_WRITE)
-    RCU_band_select_R = attribute_wrapper(comms_annotation=["RCU_band_select_R"], datatype=numpy.int64, dims=(N_rcu, N_rcu_inp))
-    RCU_band_select_RW = attribute_wrapper(comms_annotation=["RCU_band_select_RW"], datatype=numpy.int64, dims=(N_rcu, N_rcu_inp),
-                                           access=AttrWriteType.READ_WRITE)
-    RCU_DTH_freq_R = attribute_wrapper(comms_annotation=["RCU_DTH_freq_R"], datatype=numpy.int64, dims=(N_rcu, N_rcu_inp))
-    RCU_DTH_freq_RW = attribute_wrapper(comms_annotation=["RCU_DTH_freq_RW"], datatype=numpy.int64, dims=(N_rcu, N_rcu_inp),
-                                        access=AttrWriteType.READ_WRITE)
-    RCU_DTH_on_R = attribute_wrapper(comms_annotation=["RCU_DTH_on_R"], datatype=bool, dims=(N_rcu, N_rcu_inp))
-    RCU_LED_green_on_R = attribute_wrapper(comms_annotation=["RCU_LED_green_on_R"], datatype=bool, dims=(N_rcu,))
-    RCU_LED_green_on_RW = attribute_wrapper(comms_annotation=["RCU_LED_green_on_RW"], datatype=bool, dims=(N_rcu,),
-                                            access=AttrWriteType.READ_WRITE)
-    RCU_LED_red_on_R = attribute_wrapper(comms_annotation=["RCU_LED_red_on_R"], datatype=bool, dims=(N_rcu,))
-    RCU_LED_red_on_RW = attribute_wrapper(comms_annotation=["RCU_LED_red_on_RW"], datatype=bool, dims=(N_rcu,),
-                                          access=AttrWriteType.READ_WRITE)
-    RCU_mask_RW = attribute_wrapper(comms_annotation=["RCU_mask_RW"], datatype=bool, dims=(N_rcu,),
-                                    access=AttrWriteType.READ_WRITE)
-    RCU_PCB_ID_R = attribute_wrapper(comms_annotation=["RCU_PCB_ID_R"], datatype=numpy.int64, dims=(N_rcu,))
-    RCU_PCB_number_R = attribute_wrapper(comms_annotation=["RCU_PCB_number_R"], datatype=str, dims=(N_rcu,))
-    RCU_PCB_version_R = attribute_wrapper(comms_annotation=["RCU_PCB_version_R"], datatype=str, dims=(N_rcu,))
-    RCU_PWR_1V8_R = attribute_wrapper(comms_annotation=["RCU_PWR_1V8_R"], datatype=numpy.float64, dims=(N_rcu,))
-    RCU_PWR_2V5_R = attribute_wrapper(comms_annotation=["RCU_PWR_2V5_R"], datatype=numpy.float64, dims=(N_rcu,))
-    RCU_PWR_3V3_R = attribute_wrapper(comms_annotation=["RCU_PWR_3V3_R"], datatype=numpy.float64, dims=(N_rcu,))
-    RCU_PWR_ANALOG_on_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANALOG_on_R"], datatype=bool, dims=(N_rcu,))
-    RCU_PWR_ANT_IOUT_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_IOUT_R"], datatype=numpy.float64,
-                                           dims=(N_rcu, N_rcu_inp))
-    RCU_PWR_ANT_on_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_on_R"], datatype=bool, dims=(N_rcu, N_rcu_inp))
-    RCU_PWR_ANT_on_RW = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_on_RW"], datatype=bool, dims=(N_rcu, N_rcu_inp),
-                                          access=AttrWriteType.READ_WRITE)
-    RCU_PWR_ANT_VIN_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_VIN_R"], datatype=numpy.float64, dims=(N_rcu, N_rcu_inp))
-    RCU_PWR_ANT_VOUT_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_VOUT_R"], datatype=numpy.float64,
-                                           dims=(N_rcu, N_rcu_inp))
-    RCU_PWR_DIGITAL_on_R = attribute_wrapper(comms_annotation=["RCU_PWR_DIGITAL_on_R"], datatype=bool, dims=(N_rcu,))
-    RCU_PWR_good_R = attribute_wrapper(comms_annotation=["RCU_PWR_good_R"], datatype=bool, dims=(N_rcu,))
-    RCU_TEMP_R = attribute_wrapper(comms_annotation=["RCU_TEMP_R"], datatype=numpy.float64, dims=(N_rcu,))
-    RECVTR_I2C_error_R = attribute_wrapper(comms_annotation=["RECVTR_I2C_error_R"], datatype=numpy.int64, dims=(N_rcu,))
-    RECVTR_monitor_rate_RW = attribute_wrapper(comms_annotation=["RECVTR_monitor_rate_RW"], datatype=numpy.int64,
-                                               access=AttrWriteType.READ_WRITE)
-    RECVTR_translator_busy_R = attribute_wrapper(comms_annotation=["RECVTR_translator_busy_R"], datatype=bool)
+    # The 32 delays deconstruct as delays[polarisation][dipole],
+    # and each delay is the number of 'delay steps' to apply (0.5ns for HBAT1).
+    HBAT_BF_delay_steps_R = AttributeWrapper(
+        comms_annotation=["HBAT_BF_delay_steps_R"], datatype=numpy.int64,
+        dims=(N_rcu * N_rcu_inp, N_elements, N_pol)
+    )
+    HBAT_BF_delay_steps_RW = AttributeWrapper(
+        comms_annotation=["HBAT_BF_delay_steps_RW"], datatype=numpy.int64,
+        dims=(N_rcu * N_rcu_inp, N_elements, N_pol),
+        access=AttrWriteType.READ_WRITE
+    )
+    HBAT_LED_on_R = AttributeWrapper(
+        comms_annotation=["HBAT_LED_on_R"], datatype=bool,
+        dims=(N_rcu * N_rcu_inp, N_elements, N_pol)
+    )
+    HBAT_LED_on_RW = AttributeWrapper(
+        comms_annotation=["HBAT_LED_on_RW"], datatype=bool,
+        dims=(N_rcu * N_rcu_inp, N_elements, N_pol),
+        access=AttrWriteType.READ_WRITE
+    )
+    HBAT_PWR_LNA_on_R = AttributeWrapper(
+        comms_annotation=["HBAT_PWR_LNA_on_R"], datatype=bool,
+        dims=(N_rcu * N_rcu_inp, N_elements, N_pol)
+    )
+    HBAT_PWR_LNA_on_RW = AttributeWrapper(
+        comms_annotation=["HBAT_PWR_LNA_on_RW"], datatype=bool,
+        dims=(N_rcu * N_rcu_inp, N_elements, N_pol),
+        access=AttrWriteType.READ_WRITE
+    )
+    HBAT_PWR_on_R = AttributeWrapper(
+        comms_annotation=["HBAT_PWR_on_R"], datatype=bool,
+        dims=(N_rcu * N_rcu_inp, N_elements, N_pol)
+    )
+    HBAT_PWR_on_RW = AttributeWrapper(
+        comms_annotation=["HBAT_PWR_on_RW"], datatype=bool,
+        dims=(N_rcu * N_rcu_inp, N_elements, N_pol),
+        access=AttrWriteType.READ_WRITE
+    )
+    RCU_ADC_locked_R = AttributeWrapper(
+        comms_annotation=["RCU_ADC_locked_R"], datatype=bool,
+        dims=(N_rcu, N_rcu_inp)
+    )
+    RCU_attenuator_dB_R = AttributeWrapper(
+        comms_annotation=["RCU_attenuator_dB_R"], datatype=numpy.int64,
+        dims=(N_rcu, N_rcu_inp)
+    )
+    RCU_attenuator_dB_RW = AttributeWrapper(
+        comms_annotation=["RCU_attenuator_dB_RW"], datatype=numpy.int64,
+        dims=(N_rcu, N_rcu_inp), access=AttrWriteType.READ_WRITE
+    )
+    RCU_band_select_R = AttributeWrapper(
+        comms_annotation=["RCU_band_select_R"], datatype=numpy.int64,
+        dims=(N_rcu, N_rcu_inp)
+    )
+    RCU_band_select_RW = AttributeWrapper(
+        comms_annotation=["RCU_band_select_RW"], datatype=numpy.int64,
+        dims=(N_rcu, N_rcu_inp), access=AttrWriteType.READ_WRITE
+    )
+    RCU_DTH_freq_R = AttributeWrapper(
+        comms_annotation=["RCU_DTH_freq_R"], datatype=numpy.int64,
+        dims=(N_rcu, N_rcu_inp)
+    )
+    RCU_DTH_freq_RW = AttributeWrapper(
+        comms_annotation=["RCU_DTH_freq_RW"], datatype=numpy.int64,
+        dims=(N_rcu, N_rcu_inp),
+        access=AttrWriteType.READ_WRITE
+    )
+    RCU_DTH_on_R = AttributeWrapper(
+        comms_annotation=["RCU_DTH_on_R"], datatype=bool,
+        dims=(N_rcu, N_rcu_inp)
+    )
+    RCU_LED_green_on_R = AttributeWrapper(
+        comms_annotation=["RCU_LED_green_on_R"], datatype=bool,
+        dims=(N_rcu,)
+    )
+    RCU_LED_green_on_RW = AttributeWrapper(
+        comms_annotation=["RCU_LED_green_on_RW"], datatype=bool,
+        dims=(N_rcu,), access=AttrWriteType.READ_WRITE
+    )
+    RCU_LED_red_on_R = AttributeWrapper(
+        comms_annotation=["RCU_LED_red_on_R"], datatype=bool,
+        dims=(N_rcu,)
+    )
+    RCU_LED_red_on_RW = AttributeWrapper(
+        comms_annotation=["RCU_LED_red_on_RW"], datatype=bool,
+        dims=(N_rcu,), access=AttrWriteType.READ_WRITE
+    )
+    RCU_mask_RW = AttributeWrapper(
+        comms_annotation=["RCU_mask_RW"], datatype=bool, dims=(N_rcu,),
+        access=AttrWriteType.READ_WRITE
+    )
+    RCU_PCB_ID_R = AttributeWrapper(comms_annotation=["RCU_PCB_ID_R"], datatype=numpy.int64, dims=(N_rcu,))
+    RCU_PCB_number_R = AttributeWrapper(comms_annotation=["RCU_PCB_number_R"], datatype=str, dims=(N_rcu,))
+    RCU_PCB_version_R = AttributeWrapper(comms_annotation=["RCU_PCB_version_R"], datatype=str, dims=(N_rcu,))
+    RCU_PWR_1V8_R = AttributeWrapper(comms_annotation=["RCU_PWR_1V8_R"], datatype=numpy.float64, dims=(N_rcu,))
+    RCU_PWR_2V5_R = AttributeWrapper(comms_annotation=["RCU_PWR_2V5_R"], datatype=numpy.float64, dims=(N_rcu,))
+    RCU_PWR_3V3_R = AttributeWrapper(comms_annotation=["RCU_PWR_3V3_R"], datatype=numpy.float64, dims=(N_rcu,))
+    RCU_PWR_ANALOG_on_R = AttributeWrapper(comms_annotation=["RCU_PWR_ANALOG_on_R"], datatype=bool, dims=(N_rcu,))
+    RCU_PWR_ANT_IOUT_R = AttributeWrapper(comms_annotation=["RCU_PWR_ANT_IOUT_R"], datatype=numpy.float64, dims=(N_rcu, N_rcu_inp))
+    RCU_PWR_ANT_on_R = AttributeWrapper(comms_annotation=["RCU_PWR_ANT_on_R"], datatype=bool, dims=(N_rcu, N_rcu_inp))
+    RCU_PWR_ANT_on_RW = AttributeWrapper(comms_annotation=["RCU_PWR_ANT_on_RW"], datatype=bool, dims=(N_rcu, N_rcu_inp), access=AttrWriteType.READ_WRITE)
+    RCU_PWR_ANT_VIN_R = AttributeWrapper(comms_annotation=["RCU_PWR_ANT_VIN_R"], datatype=numpy.float64, dims=(N_rcu, N_rcu_inp))
+    RCU_PWR_ANT_VOUT_R = AttributeWrapper(comms_annotation=["RCU_PWR_ANT_VOUT_R"], datatype=numpy.float64, dims=(N_rcu, N_rcu_inp))
+    RCU_PWR_DIGITAL_on_R = AttributeWrapper(comms_annotation=["RCU_PWR_DIGITAL_on_R"], datatype=bool, dims=(N_rcu,))
+    RCU_PWR_good_R = AttributeWrapper(comms_annotation=["RCU_PWR_good_R"], datatype=bool, dims=(N_rcu,))
+    RCU_TEMP_R = AttributeWrapper(comms_annotation=["RCU_TEMP_R"], datatype=numpy.float64, dims=(N_rcu,))
+    RECVTR_I2C_error_R = AttributeWrapper(comms_annotation=["RECVTR_I2C_error_R"], datatype=numpy.int64, dims=(N_rcu,))
+    RECVTR_monitor_rate_RW = AttributeWrapper(comms_annotation=["RECVTR_monitor_rate_RW"], datatype=numpy.int64, access=AttrWriteType.READ_WRITE)
+    RECVTR_translator_busy_R = AttributeWrapper(comms_annotation=["RECVTR_translator_busy_R"], datatype=bool)
 
     # ----------
     # Summarising Attributes
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
index 68cb16d1aea06aa45e427acedbdb1d57694cf798..bc7bc84819f2344b625c30072691394a8830facd 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
@@ -15,9 +15,9 @@ from tango import AttrWriteType, DevVarFloatArray, DevVarULongArray, DeviceProxy
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import log_exceptions
 from tangostationcontrol.common.constants import N_pn, A_pn, N_pol, N_beamlets_ctrl, N_beamsets_ctrl, P_sum, DEFAULT_SUBBAND
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
-from tangostationcontrol.devices.opcua_device import opcua_device
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
 from tangostationcontrol.devices.sdp.common import phases_to_weights, subband_frequencies
+from tangostationcontrol.devices.opcua_device import OPCUADevice
 
 import numpy
 from functools import lru_cache
@@ -28,7 +28,7 @@ import logging
 logger = logging.getLogger()
 
 
-class Beamlet(opcua_device):
+class Beamlet(OPCUADevice):
 
     # -----------------
     # Device Properties
@@ -103,88 +103,88 @@ class Beamlet(opcua_device):
     # Attributes
     # ----------
 
-    FPGA_beamlet_output_enable_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_R"], datatype=bool, dims=(N_pn,))
-    FPGA_beamlet_output_enable_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)   
+    FPGA_beamlet_output_enable_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_enable_R"], datatype=bool, dims=(N_pn,))
+    FPGA_beamlet_output_enable_RW = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
     
-    FPGA_beamlet_output_hdr_eth_source_mac_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_source_mac_R"], datatype=str, dims=(N_pn,))
-    FPGA_beamlet_output_hdr_eth_source_mac_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_source_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_hdr_ip_source_address_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_source_address_R"], datatype=str, dims=(N_pn,))
-    FPGA_beamlet_output_hdr_ip_source_address_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_source_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_hdr_udp_source_port_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_source_port_R"], datatype=numpy.uint16, dims=(N_pn,))
-    FPGA_beamlet_output_hdr_udp_source_port_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_source_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_eth_source_mac_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_source_mac_R"], datatype=str, dims=(N_pn,))
+    FPGA_beamlet_output_hdr_eth_source_mac_RW = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_source_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_ip_source_address_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_source_address_R"], datatype=str, dims=(N_pn,))
+    FPGA_beamlet_output_hdr_ip_source_address_RW = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_source_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_udp_source_port_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_source_port_R"], datatype=numpy.uint16, dims=(N_pn,))
+    FPGA_beamlet_output_hdr_udp_source_port_RW = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_source_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
     
-    FPGA_beamlet_output_hdr_eth_destination_mac_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_R"], datatype=str, dims=(N_pn,))
-    FPGA_beamlet_output_hdr_eth_destination_mac_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_hdr_ip_destination_address_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_R"], datatype=str, dims=(N_pn,))
-    FPGA_beamlet_output_hdr_ip_destination_address_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_hdr_udp_destination_port_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_pn,))
-    FPGA_beamlet_output_hdr_udp_destination_port_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_eth_destination_mac_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_R"], datatype=str, dims=(N_pn,))
+    FPGA_beamlet_output_hdr_eth_destination_mac_RW = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_ip_destination_address_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_R"], datatype=str, dims=(N_pn,))
+    FPGA_beamlet_output_hdr_ip_destination_address_RW = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_udp_destination_port_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_pn,))
+    FPGA_beamlet_output_hdr_udp_destination_port_RW = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
     
-    FPGA_beamlet_output_scale_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_R"], datatype=numpy.double, dims=(N_pn,))
-    FPGA_beamlet_output_scale_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_RW"], datatype=numpy.double, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_bsn_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_bsn_R"], datatype=numpy.int64, dims=(N_pn, N_beamsets_ctrl))
+    FPGA_beamlet_output_scale_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_scale_R"], datatype=numpy.double, dims=(N_pn,))
+    FPGA_beamlet_output_scale_RW = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_scale_RW"], datatype=numpy.double, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_bsn_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_bsn_R"], datatype=numpy.int64, dims=(N_pn, N_beamsets_ctrl))
 
-    FPGA_beamlet_output_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_nof_packets_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl))
-    FPGA_beamlet_output_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_nof_valid_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl))
+    FPGA_beamlet_output_nof_packets_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_nof_packets_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl))
+    FPGA_beamlet_output_nof_valid_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_nof_valid_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl))
 
     # boolean[N_pn][N_beamsets_ctrl]
-    FPGA_beamlet_output_ready_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_ready_R"], datatype=bool, dims=(N_pn, N_beamsets_ctrl))
+    FPGA_beamlet_output_ready_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_ready_R"], datatype=bool, dims=(N_pn, N_beamsets_ctrl))
     # boolean[N_pn][N_beamsets_ctrl]
-    FPGA_beamlet_output_xon_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_xon_R"], datatype=bool, dims=(N_pn, N_beamsets_ctrl))
+    FPGA_beamlet_output_xon_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_output_xon_R"], datatype=bool, dims=(N_pn, N_beamsets_ctrl))
 
     # uint16[N_pn][A_PN][N_POL][N_beamsets_ctrl]
     # Select subband per dual-polarisation beamlet.
     # 0 for antenna polarization X in beamlet polarization X,
     # 1 for antenna polarization Y in beamlet polarization Y.
-    FPGA_beamlet_subband_select_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_subband_select_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_pol, N_beamlets_ctrl))
-    FPGA_beamlet_subband_select_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_subband_select_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_pol, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_subband_select_R = AttributeWrapper(comms_annotation=["FPGA_beamlet_subband_select_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_pol, N_beamlets_ctrl))
+    FPGA_beamlet_subband_select_RW = AttributeWrapper(comms_annotation=["FPGA_beamlet_subband_select_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_pol, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
 
     # uint32[N_pn][N_beamset_ctrl]
-    FPGA_bf_ring_nof_transport_hops_R = attribute_wrapper(comms_annotation=["FPGA_bf_ring_nof_transport_hops_R"], datatype=numpy.uint32, dims=(N_pn, N_beamsets_ctrl))
-    FPGA_bf_ring_nof_transport_hops_RW = attribute_wrapper(comms_annotation=["FPGA_bf_ring_nof_transport_hops_RW"], datatype=numpy.uint32, dims=(N_pn, N_beamsets_ctrl), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_ring_nof_transport_hops_R = AttributeWrapper(comms_annotation=["FPGA_bf_ring_nof_transport_hops_R"], datatype=numpy.uint32, dims=(N_pn, N_beamsets_ctrl))
+    FPGA_bf_ring_nof_transport_hops_RW = AttributeWrapper(comms_annotation=["FPGA_bf_ring_nof_transport_hops_RW"], datatype=numpy.uint32, dims=(N_pn, N_beamsets_ctrl), access=AttrWriteType.READ_WRITE)
 
     # cint16[N_pn][A_pn][N_pol][N_beamlets_ctrl]
     # Co-polarization BF weights. The N_pol = 2 parameter index is:
     # 0 for antenna polarization X in beamlet polarization X,
     # 1 for antenna polarization Y in beamlet polarization Y.
-    FPGA_bf_weights_xx_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_yy_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_pol, N_beamlets_ctrl))
-    FPGA_bf_weights_xx_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_yy_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_pol, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xx_yy_R = AttributeWrapper(comms_annotation=["FPGA_bf_weights_xx_yy_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_pol, N_beamlets_ctrl))
+    FPGA_bf_weights_xx_yy_RW = AttributeWrapper(comms_annotation=["FPGA_bf_weights_xx_yy_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_pol, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
 
     # cint16[N_pn][A_pn][N_pol][N_beamlets_ctrl]
     # Cross-polarization BF weights. The N_pol = 2 parameter index is (note that index pol in range 0:N_pol-1 is the antenna polarization, so index !pol is the beamlet polarization):
     # 0 for antenna polarization X in beamlet polarization Y,
     # 1 for antenna polarization Y in beamlet polarization X.
-    FPGA_bf_weights_xy_yx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_yx_R"], datatype=numpy.uint32, dims=(A_pn * N_pol * N_beamlets_ctrl, N_pn))
-    FPGA_bf_weights_xy_yx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_yx_RW"], datatype=numpy.uint32, dims=(A_pn * N_pol * N_beamlets_ctrl, N_pn), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xy_yx_R = AttributeWrapper(comms_annotation=["FPGA_bf_weights_xy_yx_R"], datatype=numpy.uint32, dims=(A_pn * N_pol * N_beamlets_ctrl, N_pn))
+    FPGA_bf_weights_xy_yx_RW = AttributeWrapper(comms_annotation=["FPGA_bf_weights_xy_yx_RW"], datatype=numpy.uint32, dims=(A_pn * N_pol * N_beamlets_ctrl, N_pn), access=AttrWriteType.READ_WRITE)
 
     # cint16[N_pn][N_pol][A_pn][N_pol][N_beamlets_ctrl]
     # Full Jones matrix of BF weights.
-    FPGA_bf_weights_xx_xy_yx_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_R"], datatype=numpy.uint32, dims=(N_pn, N_pol, A_pn, N_pol, N_beamlets_ctrl))
-    FPGA_bf_weights_xx_xy_yx_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_RW"], datatype=numpy.uint32, dims=(N_pn, N_pol, A_pn, N_pol, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xx_xy_yx_yy_R = AttributeWrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_R"], datatype=numpy.uint32, dims=(N_pn, N_pol, A_pn, N_pol, N_beamlets_ctrl))
+    FPGA_bf_weights_xx_xy_yx_yy_RW = AttributeWrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_RW"], datatype=numpy.uint32, dims=(N_pn, N_pol, A_pn, N_pol, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
 
     # cint16[N_pn][A_pn][N_beamlets_ctrl]
     # BF weights for separate access to respectively w_xx, w_xy, w_yx, and w_yy.
-    FPGA_bf_weights_xx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl))
-    FPGA_bf_weights_xx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn * N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
-    FPGA_bf_weights_xy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl))
-    FPGA_bf_weights_xy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
-    FPGA_bf_weights_yx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yx_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl))
-    FPGA_bf_weights_yx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yx_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
-    FPGA_bf_weights_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl))
-    FPGA_bf_weights_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xx_R = AttributeWrapper(comms_annotation=["FPGA_bf_weights_xx_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl))
+    FPGA_bf_weights_xx_RW = AttributeWrapper(comms_annotation=["FPGA_bf_weights_xx_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn * N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xy_R = AttributeWrapper(comms_annotation=["FPGA_bf_weights_xy_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl))
+    FPGA_bf_weights_xy_RW = AttributeWrapper(comms_annotation=["FPGA_bf_weights_xy_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_yx_R = AttributeWrapper(comms_annotation=["FPGA_bf_weights_yx_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl))
+    FPGA_bf_weights_yx_RW = AttributeWrapper(comms_annotation=["FPGA_bf_weights_yx_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_yy_R = AttributeWrapper(comms_annotation=["FPGA_bf_weights_yy_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl))
+    FPGA_bf_weights_yy_RW = AttributeWrapper(comms_annotation=["FPGA_bf_weights_yy_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
 
     # boolean[N_pn][N_beamsets_ctrl][P_sum]
-    FPGA_bf_rx_align_stream_enable_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_stream_enable_R"], datatype=bool, dims=(N_pn, N_beamsets_ctrl, P_sum))
-    FPGA_bf_rx_align_stream_enable_RW = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_stream_enable_RW"], datatype=bool, dims=(N_pn, N_beamsets_ctrl, P_sum), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_rx_align_stream_enable_R = AttributeWrapper(comms_annotation=["FPGA_bf_rx_align_stream_enable_R"], datatype=bool, dims=(N_pn, N_beamsets_ctrl, P_sum))
+    FPGA_bf_rx_align_stream_enable_RW = AttributeWrapper(comms_annotation=["FPGA_bf_rx_align_stream_enable_RW"], datatype=bool, dims=(N_pn, N_beamsets_ctrl, P_sum), access=AttrWriteType.READ_WRITE)
 
     # int64[N_pn][N_beamsets_ctrl][P_sum]
-    FPGA_bf_rx_align_bsn_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_bsn_R"], datatype=numpy.int64, dims=(N_pn, N_beamsets_ctrl, P_sum))
+    FPGA_bf_rx_align_bsn_R = AttributeWrapper(comms_annotation=["FPGA_bf_rx_align_bsn_R"], datatype=numpy.int64, dims=(N_pn, N_beamsets_ctrl, P_sum))
 
     #int32[N_pn][N_beamsets_ctrl][P_sum]
-    FPGA_bf_rx_align_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_nof_packets_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl, P_sum))
-    FPGA_bf_rx_align_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_nof_valid_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl, P_sum))
-    FPGA_bf_rx_align_latency_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_latency_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl, P_sum))
-    FPGA_bf_rx_align_nof_replaced_packets_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_nof_replaced_packets_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl, P_sum))
+    FPGA_bf_rx_align_nof_packets_R = AttributeWrapper(comms_annotation=["FPGA_bf_rx_align_nof_packets_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl, P_sum))
+    FPGA_bf_rx_align_nof_valid_R = AttributeWrapper(comms_annotation=["FPGA_bf_rx_align_nof_valid_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl, P_sum))
+    FPGA_bf_rx_align_latency_R = AttributeWrapper(comms_annotation=["FPGA_bf_rx_align_latency_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl, P_sum))
+    FPGA_bf_rx_align_nof_replaced_packets_R = AttributeWrapper(comms_annotation=["FPGA_bf_rx_align_nof_replaced_packets_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl, P_sum))
 
     subband_select_RW = attribute(dtype=(numpy.uint32,), max_dim_x=N_beamlets_ctrl, access=AttrWriteType.READ_WRITE, fisallowed="is_attribute_access_allowed")
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py
index af885a5f4cd5f5c1c6602928385765bd2e75d55c..a5b374d642f824ba7ed0f9406506d704974a50e4 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py
@@ -21,7 +21,7 @@ from lofar_station_client.statistics.collector import BSTCollector
 # Own imports
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.constants import N_pn, BST_MAX_BLOCKS, N_beamlets_max
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
 from tangostationcontrol.clients.opcua_client import OPCUAConnection
 from tangostationcontrol.clients.statistics.client import StatisticsClient
 from tangostationcontrol.devices.sdp.statistics import Statistics
@@ -70,28 +70,28 @@ class BST(Statistics):
     # ----------
 
     # FPGA control points for BSTs
-    FPGA_bst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_bst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_enable_R"], datatype=bool, dims=(N_pn,))
-    FPGA_bst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_bst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_eth_destination_mac_R"], datatype=str, dims=(N_pn,))
-    FPGA_bst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_ip_destination_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_bst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_ip_destination_address_R"], datatype=str, dims=(N_pn,))
-    FPGA_bst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_bst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_pn,))
-    FPGA_bst_offload_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
-
-    FPGA_bst_offload_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_bst_offload_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,))
-    FPGA_bst_offload_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_bst_offload_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_bst_offload_enable_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_bst_offload_enable_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_enable_R"], datatype=bool, dims=(N_pn,))
+    FPGA_bst_offload_hdr_eth_destination_mac_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_bst_offload_hdr_eth_destination_mac_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_eth_destination_mac_R"], datatype=str, dims=(N_pn,))
+    FPGA_bst_offload_hdr_ip_destination_address_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_ip_destination_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_bst_offload_hdr_ip_destination_address_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_ip_destination_address_R"], datatype=str, dims=(N_pn,))
+    FPGA_bst_offload_hdr_udp_destination_port_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_bst_offload_hdr_udp_destination_port_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_pn,))
+    FPGA_bst_offload_bsn_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
+
+    FPGA_bst_offload_nof_packets_R = AttributeWrapper(comms_annotation=["FPGA_bst_offload_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_bst_offload_nof_valid_R = AttributeWrapper(comms_annotation=["FPGA_bst_offload_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,))
 
     # number of packets with valid payloads
-    nof_valid_payloads_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(N_pn,), datatype=numpy.uint64)
+    nof_valid_payloads_R    = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(N_pn,), datatype=numpy.uint64)
     # number of packets with invalid payloads
-    nof_payload_errors_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(N_pn,), datatype=numpy.uint64)
+    nof_payload_errors_R    = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(N_pn,), datatype=numpy.uint64)
     # latest BSTs
-    bst_R                   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "bst_values"}, dims=(BST_MAX_BLOCKS, N_beamlets_max), datatype=numpy.uint64)
+    bst_R                   = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "bst_values"}, dims=(BST_MAX_BLOCKS, N_beamlets_max), datatype=numpy.uint64)
     # reported timestamp
     # for each row in the latest BSTs
-    bst_timestamp_R         = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "bst_timestamps"}, dims=(BST_MAX_BLOCKS,), datatype=numpy.uint64)
+    bst_timestamp_R         = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "bst_timestamps"}, dims=(BST_MAX_BLOCKS,), datatype=numpy.uint64)
 
     # ----------
     # Summarising Attributes
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py b/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py
index 0d8ae821e74ed2e6da552cd0399efcc0ac246f76..a025f9dd4350a6aec932ea04a6980e9cceac81b0 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py
@@ -14,7 +14,7 @@ from tango.server import attribute, AttrWriteType, device_property
 # Additional import
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.constants import N_beamlets_ctrl, MAX_ANTENNA, N_xyz, A_pn, N_pn, N_pol
-from tangostationcontrol.devices.beam_device import beam_device
+from tangostationcontrol.devices.beam_device import BeamDevice
 from tangostationcontrol.devices.device_decorators import TimeIt
 from tangostationcontrol.common.lofar_logging import log_exceptions
 from tangostationcontrol.beam.delays import Delays
@@ -28,7 +28,7 @@ logger = logging.getLogger()
 __all__ = ["DigitalBeam", "main"]
 
 
-class DigitalBeam(beam_device):
+class DigitalBeam(BeamDevice):
     """ Manages Digital Beamforming on the SDP, in which the FPGA combines
         its digital inputs from the RCUs into one or more beamlets, that
         are emitted through the Beamlet device.
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
index 4226d1d121d5be449900d0976def367513cdb5af..687667ed5320c965f724cf7f9ae9d093c8dad9d3 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
@@ -16,12 +16,12 @@ from tango.server import device_property, attribute
 from tango import AttrWriteType
 
 # Additional import
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
-from tangostationcontrol.devices.opcua_device import opcua_device
-from tangostationcontrol.devices.sdp.common import phases_to_weights, subband_frequency
+from tangostationcontrol.common.constants import S_pn, N_pn, CLK_200_MHZ, CLK_160_MHZ, N_subband_res, N_subbands, DEFAULT_SUBBAND, N_beamsets_ctrl, DEFAULT_POLLING_PERIOD
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
-from tangostationcontrol.common.constants import S_pn, N_pn, CLK_200_MHZ, CLK_160_MHZ, N_subband_res, N_subbands, DEFAULT_SUBBAND, N_beamsets_ctrl, DEFAULT_POLLING_PERIOD
+from tangostationcontrol.devices.opcua_device import OPCUADevice
+from tangostationcontrol.devices.sdp.common import phases_to_weights, subband_frequency
 
 import numpy
 
@@ -29,8 +29,7 @@ __all__ = ["SDP", "main"]
 
 
 @device_logging_to_python()
-class SDP(opcua_device):
-
+class SDP(OPCUADevice):
     # -----------------
     # Device Properties
     # -----------------
@@ -106,78 +105,78 @@ class SDP(opcua_device):
     # Attributes
     # ----------
 
-    FPGA_firmware_version_R = attribute_wrapper(comms_annotation=["FPGA_firmware_version_R"], datatype=str, dims=(N_pn,))
-    FPGA_boot_image_R = attribute_wrapper(comms_annotation=["FPGA_boot_image_R"], datatype=numpy.int32, dims=(N_pn,), doc="Active FPGA image (0=factory, 1=user)")
-    FPGA_boot_image_RW = attribute_wrapper(comms_annotation=["FPGA_boot_image_RW"], datatype=numpy.int32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_global_node_index_R = attribute_wrapper(comms_annotation=["FPGA_global_node_index_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_hardware_version_R = attribute_wrapper(comms_annotation=["FPGA_hardware_version_R"], datatype=str, dims=(N_pn,))
-    FPGA_pps_present_R = attribute_wrapper(comms_annotation=["FPGA_pps_present_R"], datatype=bool, dims=(N_pn,))
-    FPGA_pps_capture_cnt_R = attribute_wrapper(comms_annotation=["FPGA_pps_capture_cnt_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_pps_expected_cnt_R = attribute_wrapper(comms_annotation=["FPGA_pps_expected_cnt_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_pps_expected_cnt_RW = attribute_wrapper(comms_annotation=["FPGA_pps_expected_cnt_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_processing_enable_R = attribute_wrapper(comms_annotation=["FPGA_processing_enable_R"], datatype=bool, dims=(N_pn,))
-    FPGA_processing_enable_RW = attribute_wrapper(comms_annotation=["FPGA_processing_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_ring_node_offset_R = attribute_wrapper(comms_annotation=["FPGA_ring_node_offset_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_ring_node_offset_RW = attribute_wrapper(comms_annotation=["FPGA_ring_node_offset_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_ring_nof_nodes_R = attribute_wrapper(comms_annotation=["FPGA_ring_nof_nodes_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_ring_nof_nodes_RW = attribute_wrapper(comms_annotation=["FPGA_ring_nof_nodes_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_ring_use_cable_to_next_rn_R = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_next_rn_R"], datatype=bool, dims=(N_pn,))
-    FPGA_ring_use_cable_to_next_rn_RW = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_next_rn_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_ring_use_cable_to_previous_rn_R = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_previous_rn_R"], datatype=bool, dims=(N_pn,))
-    FPGA_ring_use_cable_to_previous_rn_RW = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_previous_rn_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_scrap_R = attribute_wrapper(comms_annotation=["FPGA_scrap_R"], datatype=numpy.int32, dims=(N_pn, N_subbands))
-    FPGA_scrap_RW = attribute_wrapper(comms_annotation=["FPGA_scrap_RW"], datatype=numpy.int32, dims=(N_pn, N_subbands), access=AttrWriteType.READ_WRITE)
-    FPGA_sdp_info_antenna_band_index_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_antenna_band_index_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_sdp_info_block_period_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_block_period_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_sdp_info_f_adc_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_f_adc_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_sdp_info_fsub_type_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_fsub_type_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_sdp_info_nyquist_sampling_zone_index_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_nyquist_sampling_zone_index_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_sdp_info_nyquist_sampling_zone_index_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_nyquist_sampling_zone_index_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_sdp_info_observation_id_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_observation_id_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_sdp_info_observation_id_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_observation_id_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_sdp_info_station_id_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_station_id_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_sdp_info_station_id_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_station_id_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_subband_spectral_inversion_R = attribute_wrapper(comms_annotation=["FPGA_subband_spectral_inversion_R"], datatype=bool, dims=(N_pn,))
-    FPGA_subband_spectral_inversion_RW = attribute_wrapper(comms_annotation=["FPGA_subband_spectral_inversion_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_subband_weights_R = attribute_wrapper(comms_annotation=["FPGA_subband_weights_R"], datatype=numpy.uint32, dims=(N_pn, S_pn, N_subbands))
-    FPGA_subband_weights_RW = attribute_wrapper(comms_annotation=["FPGA_subband_weights_RW"], datatype=numpy.uint32, dims=(N_pn, S_pn, N_subbands), access=AttrWriteType.READ_WRITE)
-    FPGA_time_since_last_pps_R = attribute_wrapper(comms_annotation=["FPGA_time_since_last_pps_R"], datatype=numpy.float_, dims=(N_pn,))
-    FPGA_temp_R = attribute_wrapper(comms_annotation=["FPGA_temp_R"], datatype=numpy.float_, dims=(N_pn,))
-    FPGA_wg_amplitude_R = attribute_wrapper(comms_annotation=["FPGA_wg_amplitude_R"], datatype=numpy.float_, dims=(N_pn, S_pn))
-    FPGA_wg_amplitude_RW = attribute_wrapper(comms_annotation=["FPGA_wg_amplitude_RW"], datatype=numpy.float_, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
-    FPGA_wg_enable_R = attribute_wrapper(comms_annotation=["FPGA_wg_enable_R"], datatype=bool, dims=(N_pn, S_pn))
-    FPGA_wg_enable_RW = attribute_wrapper(comms_annotation=["FPGA_wg_enable_RW"], datatype=bool, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
-    FPGA_wg_frequency_R = attribute_wrapper(comms_annotation=["FPGA_wg_frequency_R"], datatype=numpy.float_, dims=(N_pn, S_pn))
-    FPGA_wg_frequency_RW = attribute_wrapper(comms_annotation=["FPGA_wg_frequency_RW"], datatype=numpy.float_, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
-    FPGA_wg_phase_R = attribute_wrapper(comms_annotation=["FPGA_wg_phase_R"], datatype=numpy.float_, dims=(N_pn, S_pn))
-    FPGA_wg_phase_RW = attribute_wrapper(comms_annotation=["FPGA_wg_phase_RW"], datatype=numpy.float_, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
-    TR_fpga_mask_R = attribute_wrapper(comms_annotation=["TR_fpga_mask_R"], datatype=bool, dims=(N_pn,))
-    TR_fpga_mask_RW = attribute_wrapper(comms_annotation=["TR_fpga_mask_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    TR_fpga_communication_error_R = attribute_wrapper(comms_annotation=["TR_fpga_communication_error_R"], datatype=bool, dims=(N_pn,))
-    TR_sdp_config_first_fpga_nr_R = attribute_wrapper(comms_annotation=["TR_sdp_config_first_fpga_nr_R"], datatype=numpy.uint32)
-    TR_sdp_config_nof_beamsets_R = attribute_wrapper(comms_annotation=["TR_sdp_config_nof_beamsets_R"], datatype=numpy.uint32)
-    TR_sdp_config_nof_fpgas_R = attribute_wrapper(comms_annotation=["TR_sdp_config_nof_fpgas_R"], datatype=numpy.uint32)
-    TR_software_version_R = attribute_wrapper(comms_annotation=["TR_software_version_R"], datatype=str)
-    TR_start_time_R = attribute_wrapper(comms_annotation=["TR_start_time_R"], datatype=numpy.int64)
-    TR_tod_R = attribute_wrapper(comms_annotation=["TR_tod_R"], datatype=numpy.int64, dims=(2,))     # struct of (time_t, int64)
-    TR_tod_pps_delta_R = attribute_wrapper(comms_annotation=["TR_tod_pps_delta_R"], datatype=numpy.double)
+    FPGA_firmware_version_R = AttributeWrapper(comms_annotation=["FPGA_firmware_version_R"], datatype=str, dims=(N_pn,))
+    FPGA_boot_image_R = AttributeWrapper(comms_annotation=["FPGA_boot_image_R"], datatype=numpy.int32, dims=(N_pn,), doc="Active FPGA image (0=factory, 1=user)")
+    FPGA_boot_image_RW = AttributeWrapper(comms_annotation=["FPGA_boot_image_RW"], datatype=numpy.int32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_global_node_index_R = AttributeWrapper(comms_annotation=["FPGA_global_node_index_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_hardware_version_R = AttributeWrapper(comms_annotation=["FPGA_hardware_version_R"], datatype=str, dims=(N_pn,))
+    FPGA_pps_present_R = AttributeWrapper(comms_annotation=["FPGA_pps_present_R"], datatype=bool, dims=(N_pn,))
+    FPGA_pps_capture_cnt_R = AttributeWrapper(comms_annotation=["FPGA_pps_capture_cnt_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_pps_expected_cnt_R = AttributeWrapper(comms_annotation=["FPGA_pps_expected_cnt_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_pps_expected_cnt_RW = AttributeWrapper(comms_annotation=["FPGA_pps_expected_cnt_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_processing_enable_R = AttributeWrapper(comms_annotation=["FPGA_processing_enable_R"], datatype=bool, dims=(N_pn,))
+    FPGA_processing_enable_RW = AttributeWrapper(comms_annotation=["FPGA_processing_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_ring_node_offset_R = AttributeWrapper(comms_annotation=["FPGA_ring_node_offset_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_ring_node_offset_RW = AttributeWrapper(comms_annotation=["FPGA_ring_node_offset_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_ring_nof_nodes_R = AttributeWrapper(comms_annotation=["FPGA_ring_nof_nodes_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_ring_nof_nodes_RW = AttributeWrapper(comms_annotation=["FPGA_ring_nof_nodes_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_ring_use_cable_to_next_rn_R = AttributeWrapper(comms_annotation=["FPGA_ring_use_cable_to_next_rn_R"], datatype=bool, dims=(N_pn,))
+    FPGA_ring_use_cable_to_next_rn_RW = AttributeWrapper(comms_annotation=["FPGA_ring_use_cable_to_next_rn_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_ring_use_cable_to_previous_rn_R = AttributeWrapper(comms_annotation=["FPGA_ring_use_cable_to_previous_rn_R"], datatype=bool, dims=(N_pn,))
+    FPGA_ring_use_cable_to_previous_rn_RW = AttributeWrapper(comms_annotation=["FPGA_ring_use_cable_to_previous_rn_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_scrap_R = AttributeWrapper(comms_annotation=["FPGA_scrap_R"], datatype=numpy.int32, dims=(N_pn, N_subbands))
+    FPGA_scrap_RW = AttributeWrapper(comms_annotation=["FPGA_scrap_RW"], datatype=numpy.int32, dims=(N_pn, N_subbands), access=AttrWriteType.READ_WRITE)
+    FPGA_sdp_info_antenna_band_index_R = AttributeWrapper(comms_annotation=["FPGA_sdp_info_antenna_band_index_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_block_period_R = AttributeWrapper(comms_annotation=["FPGA_sdp_info_block_period_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_f_adc_R = AttributeWrapper(comms_annotation=["FPGA_sdp_info_f_adc_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_fsub_type_R = AttributeWrapper(comms_annotation=["FPGA_sdp_info_fsub_type_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_nyquist_sampling_zone_index_R = AttributeWrapper(comms_annotation=["FPGA_sdp_info_nyquist_sampling_zone_index_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_nyquist_sampling_zone_index_RW = AttributeWrapper(comms_annotation=["FPGA_sdp_info_nyquist_sampling_zone_index_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sdp_info_observation_id_R = AttributeWrapper(comms_annotation=["FPGA_sdp_info_observation_id_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_observation_id_RW = AttributeWrapper(comms_annotation=["FPGA_sdp_info_observation_id_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sdp_info_station_id_R = AttributeWrapper(comms_annotation=["FPGA_sdp_info_station_id_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_sdp_info_station_id_RW = AttributeWrapper(comms_annotation=["FPGA_sdp_info_station_id_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_subband_spectral_inversion_R = AttributeWrapper(comms_annotation=["FPGA_subband_spectral_inversion_R"], datatype=bool, dims=(N_pn,))
+    FPGA_subband_spectral_inversion_RW = AttributeWrapper(comms_annotation=["FPGA_subband_spectral_inversion_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_subband_weights_R = AttributeWrapper(comms_annotation=["FPGA_subband_weights_R"], datatype=numpy.uint32, dims=(N_pn, S_pn, N_subbands))
+    FPGA_subband_weights_RW = AttributeWrapper(comms_annotation=["FPGA_subband_weights_RW"], datatype=numpy.uint32, dims=(N_pn, S_pn, N_subbands), access=AttrWriteType.READ_WRITE)
+    FPGA_time_since_last_pps_R = AttributeWrapper(comms_annotation=["FPGA_time_since_last_pps_R"], datatype=numpy.float_, dims=(N_pn,))
+    FPGA_temp_R = AttributeWrapper(comms_annotation=["FPGA_temp_R"], datatype=numpy.float_, dims=(N_pn,))
+    FPGA_wg_amplitude_R = AttributeWrapper(comms_annotation=["FPGA_wg_amplitude_R"], datatype=numpy.float_, dims=(N_pn, S_pn))
+    FPGA_wg_amplitude_RW = AttributeWrapper(comms_annotation=["FPGA_wg_amplitude_RW"], datatype=numpy.float_, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
+    FPGA_wg_enable_R = AttributeWrapper(comms_annotation=["FPGA_wg_enable_R"], datatype=bool, dims=(N_pn, S_pn))
+    FPGA_wg_enable_RW = AttributeWrapper(comms_annotation=["FPGA_wg_enable_RW"], datatype=bool, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
+    FPGA_wg_frequency_R = AttributeWrapper(comms_annotation=["FPGA_wg_frequency_R"], datatype=numpy.float_, dims=(N_pn, S_pn))
+    FPGA_wg_frequency_RW = AttributeWrapper(comms_annotation=["FPGA_wg_frequency_RW"], datatype=numpy.float_, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
+    FPGA_wg_phase_R = AttributeWrapper(comms_annotation=["FPGA_wg_phase_R"], datatype=numpy.float_, dims=(N_pn, S_pn))
+    FPGA_wg_phase_RW = AttributeWrapper(comms_annotation=["FPGA_wg_phase_RW"], datatype=numpy.float_, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
+    TR_fpga_mask_R = AttributeWrapper(comms_annotation=["TR_fpga_mask_R"], datatype=bool, dims=(N_pn,))
+    TR_fpga_mask_RW = AttributeWrapper(comms_annotation=["TR_fpga_mask_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    TR_fpga_communication_error_R = AttributeWrapper(comms_annotation=["TR_fpga_communication_error_R"], datatype=bool, dims=(N_pn,))
+    TR_sdp_config_first_fpga_nr_R = AttributeWrapper(comms_annotation=["TR_sdp_config_first_fpga_nr_R"], datatype=numpy.uint32)
+    TR_sdp_config_nof_beamsets_R = AttributeWrapper(comms_annotation=["TR_sdp_config_nof_beamsets_R"], datatype=numpy.uint32)
+    TR_sdp_config_nof_fpgas_R = AttributeWrapper(comms_annotation=["TR_sdp_config_nof_fpgas_R"], datatype=numpy.uint32)
+    TR_software_version_R = AttributeWrapper(comms_annotation=["TR_software_version_R"], datatype=str)
+    TR_start_time_R = AttributeWrapper(comms_annotation=["TR_start_time_R"], datatype=numpy.int64)
+    TR_tod_R = AttributeWrapper(comms_annotation=["TR_tod_R"], datatype=numpy.int64, dims=(2,))     # struct of (time_t, int64)
+    TR_tod_pps_delta_R = AttributeWrapper(comms_annotation=["TR_tod_pps_delta_R"], datatype=numpy.double)
 
     # OPC-UA MP only points for AIT
-    FPGA_signal_input_mean_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_mean_R"], datatype=numpy.double , dims=(N_pn, S_pn))
-    FPGA_signal_input_rms_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_rms_R"], datatype=numpy.double, dims=(N_pn, S_pn))
+    FPGA_signal_input_mean_R = AttributeWrapper(comms_annotation=["FPGA_signal_input_mean_R"], datatype=numpy.double , dims=(N_pn, S_pn))
+    FPGA_signal_input_rms_R = AttributeWrapper(comms_annotation=["FPGA_signal_input_rms_R"], datatype=numpy.double, dims=(N_pn, S_pn))
 
-    FPGA_jesd204b_csr_rbd_count_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_csr_rbd_count_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
-    FPGA_jesd204b_csr_dev_syncn_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_csr_dev_syncn_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
-    FPGA_jesd204b_rx_err0_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_rx_err0_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
-    FPGA_jesd204b_rx_err1_R = attribute_wrapper(comms_annotation=["FPGA_jesd204b_rx_err1_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
+    FPGA_jesd204b_csr_rbd_count_R = AttributeWrapper(comms_annotation=["FPGA_jesd204b_csr_rbd_count_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
+    FPGA_jesd204b_csr_dev_syncn_R = AttributeWrapper(comms_annotation=["FPGA_jesd204b_csr_dev_syncn_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
+    FPGA_jesd204b_rx_err0_R = AttributeWrapper(comms_annotation=["FPGA_jesd204b_rx_err0_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
+    FPGA_jesd204b_rx_err1_R = AttributeWrapper(comms_annotation=["FPGA_jesd204b_rx_err1_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
 
-    FPGA_signal_input_bsn_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
-    FPGA_signal_input_nof_blocks_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_nof_blocks_R"], datatype=numpy.int32, dims=(N_pn,))
-    FPGA_signal_input_nof_samples_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_nof_samples_R"], datatype=numpy.int32, dims=(N_pn,))
-    FPGA_signal_input_samples_delay_R = attribute_wrapper(comms_annotation=["FPGA_signal_input_samples_delay_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
-    FPGA_signal_input_samples_delay_RW = attribute_wrapper(comms_annotation=["FPGA_signal_input_samples_delay_RW"], datatype=numpy.uint32, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
+    FPGA_signal_input_bsn_R = AttributeWrapper(comms_annotation=["FPGA_signal_input_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
+    FPGA_signal_input_nof_blocks_R = AttributeWrapper(comms_annotation=["FPGA_signal_input_nof_blocks_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_signal_input_nof_samples_R = AttributeWrapper(comms_annotation=["FPGA_signal_input_nof_samples_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_signal_input_samples_delay_R = AttributeWrapper(comms_annotation=["FPGA_signal_input_samples_delay_R"], datatype=numpy.uint32, dims=(N_pn, S_pn))
+    FPGA_signal_input_samples_delay_RW = AttributeWrapper(comms_annotation=["FPGA_signal_input_samples_delay_RW"], datatype=numpy.uint32, dims=(N_pn, S_pn), access=AttrWriteType.READ_WRITE)
 
-    FPGA_bst_offload_bsn_R = attribute_wrapper(comms_annotation=["FPGA_bst_offload_bsn_R"], datatype=numpy.int64, dims=(N_pn, N_beamsets_ctrl))
+    FPGA_bst_offload_bsn_R = AttributeWrapper(comms_annotation=["FPGA_bst_offload_bsn_R"], datatype=numpy.int64, dims=(N_pn, N_beamsets_ctrl))
 
     antenna_type_RW = attribute(doc='Type of antenna (LBA or HBA) attached to each input of the FPGAs',
                                  dtype=((str,),), max_dim_y=N_pn, max_dim_x=S_pn,
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
index 52faf1a74030a5a443baa25456969cf2d1ce2d42..4a90b3c12c57bcd7499ff0c4c760af42aeaeea19 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
@@ -18,7 +18,7 @@ from tango import AttrWriteType
 # Additional import
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.constants import N_pn, MAX_INPUTS, N_subbands
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
 from tangostationcontrol.clients.opcua_client import OPCUAConnection
 from tangostationcontrol.clients.statistics.client import StatisticsClient
 from tangostationcontrol.devices.sdp.statistics import Statistics
@@ -80,34 +80,34 @@ class SST(Statistics):
     # ----------
 
     # FPGA control points for SSTs
-    FPGA_sst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_sst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_enable_R"], datatype=bool, dims=(N_pn,))
-    FPGA_sst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_sst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_eth_destination_mac_R"], datatype=str, dims=(N_pn,))
-    FPGA_sst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_ip_destination_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_sst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_ip_destination_address_R"], datatype=str, dims=(N_pn,))
-    FPGA_sst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_sst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_pn,))
-    FPGA_sst_offload_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
-    FPGA_sst_offload_weighted_subbands_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_weighted_subbands_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_sst_offload_weighted_subbands_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_weighted_subbands_R"], datatype=bool, dims=(N_pn,))
-
-    FPGA_sst_offload_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_sst_offload_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,))
-    FPGA_sst_offload_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_sst_offload_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_sst_offload_enable_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sst_offload_enable_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_enable_R"], datatype=bool, dims=(N_pn,))
+    FPGA_sst_offload_hdr_eth_destination_mac_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sst_offload_hdr_eth_destination_mac_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_eth_destination_mac_R"], datatype=str, dims=(N_pn,))
+    FPGA_sst_offload_hdr_ip_destination_address_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_ip_destination_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sst_offload_hdr_ip_destination_address_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_ip_destination_address_R"], datatype=str, dims=(N_pn,))
+    FPGA_sst_offload_hdr_udp_destination_port_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sst_offload_hdr_udp_destination_port_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_pn,))
+    FPGA_sst_offload_bsn_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
+    FPGA_sst_offload_weighted_subbands_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_weighted_subbands_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sst_offload_weighted_subbands_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_weighted_subbands_R"], datatype=bool, dims=(N_pn,))
+
+    FPGA_sst_offload_nof_packets_R = AttributeWrapper(comms_annotation=["FPGA_sst_offload_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_sst_offload_nof_valid_R = AttributeWrapper(comms_annotation=["FPGA_sst_offload_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,))
 
     # number of packets with valid payloads
-    nof_valid_payloads_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(N_pn,), datatype=numpy.uint64)
+    nof_valid_payloads_R    = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(N_pn,), datatype=numpy.uint64)
     # number of packets with invalid payloads
-    nof_payload_errors_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(N_pn,), datatype=numpy.uint64)
+    nof_payload_errors_R    = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(N_pn,), datatype=numpy.uint64)
     # latest SSTs
-    sst_R                   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_values"}, dims=(MAX_INPUTS, N_subbands), datatype=numpy.uint64)
+    sst_R                   = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_values"}, dims=(MAX_INPUTS, N_subbands), datatype=numpy.uint64)
     # reported timestamp
     # for each row in the latest SSTs
-    sst_timestamp_R         = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_timestamps"}, dims=(MAX_INPUTS,), datatype=numpy.uint64)
+    sst_timestamp_R         = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_timestamps"}, dims=(MAX_INPUTS,), datatype=numpy.uint64)
     # integration interval for each row in the latest SSTs
-    integration_interval_R  = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "integration_intervals"}, dims=(MAX_INPUTS,), datatype=numpy.float32)
+    integration_interval_R  = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "integration_intervals"}, dims=(MAX_INPUTS,), datatype=numpy.float32)
     # whether the subband data was calibrated by the SDP (that is, were subband weights applied)
-    subbands_calibrated_R   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "subbands_calibrated"}, dims=(MAX_INPUTS,), datatype=bool)
+    subbands_calibrated_R   = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "subbands_calibrated"}, dims=(MAX_INPUTS,), datatype=bool)
 
     # ----------
     # Summarising Attributes
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py
index 8e2bc497a752176a96bbd7d996448a15fac36c78..535f37c08c281fe1636238bb78ab7ac5790b844a 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py
@@ -19,8 +19,8 @@ from tango import DeviceProxy, DevSource
 import asyncio
 
 from tangostationcontrol.clients.statistics.client import StatisticsClient
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
-from tangostationcontrol.devices.opcua_device import opcua_device
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
+from tangostationcontrol.devices.opcua_device import OPCUADevice
 from tangostationcontrol.common.lofar_logging import log_exceptions
 from tangostationcontrol.common.constants import MAX_ETH_FRAME_SIZE
 
@@ -33,7 +33,7 @@ import numpy
 __all__ = ["Statistics"]
 
 
-class Statistics(opcua_device):
+class Statistics(OPCUADevice):
 
     # In derived classes, set this to a subclass of StatisticsCollector
     @property
@@ -62,34 +62,34 @@ class Statistics(opcua_device):
     # ----------
 
     # number of UDP packets and bytes that were received
-    nof_packets_received_R  = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "nof_packets_received"}, datatype=numpy.uint64)
-    nof_bytes_received_R  = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "nof_bytes_received"}, datatype=numpy.uint64)
+    nof_packets_received_R  = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "nof_packets_received"}, datatype=numpy.uint64)
+    nof_bytes_received_R  = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "nof_bytes_received"}, datatype=numpy.uint64)
     # number of UDP packets that were dropped because we couldn't keep up with processing
-    nof_packets_dropped_R   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "nof_packets_dropped"}, datatype=numpy.uint64)
+    nof_packets_dropped_R   = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "nof_packets_dropped"}, datatype=numpy.uint64)
     # last packet we processed
-    last_packet_R           = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "last_packet"}, dims=(MAX_ETH_FRAME_SIZE,), datatype=numpy.uint8)
+    last_packet_R           = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "last_packet"}, dims=(MAX_ETH_FRAME_SIZE,), datatype=numpy.uint8)
     # when last packet was received
-    last_packet_timestamp_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "last_packet_timestamp"}, datatype=numpy.uint64)
+    last_packet_timestamp_R = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "last_packet_timestamp"}, datatype=numpy.uint64)
 
 
     # queue fill percentage, as reported by the consumer
-    queue_collector_fill_percentage_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "queue", "parameter": "collector_fill_percentage"}, datatype=numpy.uint64)
-    queue_replicator_fill_percentage_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "queue", "parameter": "replicator_fill_percentage"}, datatype=numpy.uint64)
+    queue_collector_fill_percentage_R = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "queue", "parameter": "collector_fill_percentage"}, datatype=numpy.uint64)
+    queue_replicator_fill_percentage_R = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "queue", "parameter": "replicator_fill_percentage"}, datatype=numpy.uint64)
 
-    replicator_clients_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "clients"}, dims=(MAX_STATISTICS_CLIENTS,), datatype=str)
-    replicator_nof_bytes_sent_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "nof_bytes_sent"}, datatype=numpy.uint64)
+    replicator_clients_R = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "clients"}, dims=(MAX_STATISTICS_CLIENTS,), datatype=str)
+    replicator_nof_bytes_sent_R = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "nof_bytes_sent"}, datatype=numpy.uint64)
 
-    replicator_nof_packets_sent_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "nof_packets_sent"}, datatype=numpy.uint64)
-    replicator_nof_tasks_pending_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "nof_tasks_pending"}, datatype=numpy.uint64)
+    replicator_nof_packets_sent_R = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "nof_packets_sent"}, datatype=numpy.uint64)
+    replicator_nof_tasks_pending_R = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "nof_tasks_pending"}, datatype=numpy.uint64)
 
     # number of UDP packets that were processed
-    nof_packets_processed_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_packets"}, datatype=numpy.uint64)
+    nof_packets_processed_R = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_packets"}, datatype=numpy.uint64)
     # number of invalid (non-SST) packets received
-    nof_invalid_packets_R   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_invalid_packets"}, datatype=numpy.uint64)
+    nof_invalid_packets_R   = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_invalid_packets"}, datatype=numpy.uint64)
     # last packet that could not be parsed
-    last_invalid_packet_R   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "last_invalid_packet"}, dims=(MAX_ETH_FRAME_SIZE,), datatype=numpy.uint8)
+    last_invalid_packet_R   = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "last_invalid_packet"}, dims=(MAX_ETH_FRAME_SIZE,), datatype=numpy.uint8)
     # what the last exception was
-    last_invalid_packet_exception_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "last_invalid_packet_exception"}, datatype=str)
+    last_invalid_packet_exception_R = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "last_invalid_packet_exception"}, datatype=str)
 
     # --------
     # Overloaded functions
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
index f39bbb3843377f77229e4a91f3fcde23443f3ad0..5b1628702e32f63c9a364dfbcd116d27095f784f 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
@@ -20,7 +20,7 @@ from lofar_station_client.statistics.collector import XSTCollector
 # Additional import
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.constants import N_pn, P_sq, DEFAULT_SUBBAND, MAX_PARALLEL_SUBBANDS, MAX_BLOCKS, BLOCK_LENGTH, VALUES_PER_COMPLEX, MAX_INPUTS
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
 from tangostationcontrol.clients.opcua_client import OPCUAConnection
 from tangostationcontrol.clients.statistics.client import StatisticsClient
 
@@ -95,70 +95,70 @@ class XST(Statistics):
     # ----------
 
     # FPGA control points for XSTs
-    FPGA_xst_integration_interval_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_integration_interval_RW"], datatype=numpy.double, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_integration_interval_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_integration_interval_R"], datatype=numpy.double, dims=(N_pn,))
-    FPGA_xst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_enable_R"], datatype=bool, dims=(N_pn,))
-    FPGA_xst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_eth_destination_mac_R"], datatype=str, dims=(N_pn,))
-    FPGA_xst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_ip_destination_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_ip_destination_address_R"], datatype=str, dims=(N_pn,))
-    FPGA_xst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_pn,))
-    FPGA_xst_offload_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
-    FPGA_xst_processing_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_processing_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_processing_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_processing_enable_R"], datatype=bool, dims=(N_pn,))
-    FPGA_xst_subband_select_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_subband_select_RW"], datatype=numpy.uint32, dims=(MAX_PARALLEL_SUBBANDS,N_pn), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_subband_select_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_subband_select_R"], datatype=numpy.uint32, dims=(MAX_PARALLEL_SUBBANDS,N_pn))
-
-    FPGA_xst_offload_nof_crosslets_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_nof_crosslets_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_offload_nof_crosslets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_nof_crosslets_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_xst_ring_nof_transport_hops_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_nof_transport_hops_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_ring_nof_transport_hops_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_nof_transport_hops_R"], datatype=numpy.uint32, dims=(N_pn,))
-
-    FPGA_xst_offload_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_xst_offload_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,))
-    FPGA_xst_offload_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_xst_offload_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,))
-
-    FPGA_xst_ring_rx_clear_total_counts_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_clear_total_counts_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_ring_rx_clear_total_counts_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_clear_total_counts_R"], datatype=bool, dims=(N_pn,))
-    FPGA_xst_rx_align_stream_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_stream_enable_RW"], datatype=bool, dims=(N_pn,P_sq), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_rx_align_stream_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_stream_enable_R"], datatype=bool, dims=(N_pn,P_sq))
-    FPGA_xst_ring_rx_total_nof_packets_received_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_packets_received_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_xst_ring_rx_total_nof_packets_discarded_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_packets_discarded_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_xst_ring_rx_total_nof_sync_received_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_sync_received_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_xst_ring_rx_total_nof_sync_discarded_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_sync_discarded_R"], datatype=numpy.uint32, dims=(N_pn,))
-    FPGA_xst_ring_rx_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_bsn_R"], datatype=numpy.int64, dims=(N_pn, N_pn))
-    FPGA_xst_ring_rx_nof_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_nof_packets_R"], datatype=numpy.int32, dims=(N_pn, N_pn))
-    FPGA_xst_ring_rx_nof_valid_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_nof_valid_R"], datatype=numpy.int32, dims=(N_pn, N_pn))
-    FPGA_xst_ring_rx_latency_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_latency_R"], datatype=numpy.int32, dims=(N_pn, N_pn))
-    FPGA_xst_rx_align_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_bsn_R"], datatype=numpy.int64, dims=(N_pn,P_sq))
-    FPGA_xst_rx_align_nof_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,P_sq))
-    FPGA_xst_rx_align_nof_valid_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,P_sq))
-    FPGA_xst_rx_align_latency_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_latency_R"], datatype=numpy.int32, dims=(N_pn,P_sq))
-    FPGA_xst_rx_align_nof_replaced_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_nof_replaced_packets_R"], datatype=numpy.int32, dims=(N_pn,P_sq))
-    FPGA_xst_aligned_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
-    FPGA_xst_aligned_nof_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,))
-    FPGA_xst_aligned_nof_valid_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,))
-    FPGA_xst_aligned_latency_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_latency_R"], datatype=numpy.int32, dims=(N_pn,))
-    FPGA_xst_ring_tx_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_bsn_R"], datatype=numpy.int64, dims=(N_pn,N_pn))
-    FPGA_xst_ring_tx_nof_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,N_pn))
-    FPGA_xst_ring_tx_nof_valid_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,N_pn))
-    FPGA_xst_ring_tx_latency_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_latency_R"], datatype=numpy.int32, dims=(N_pn,N_pn))
+    FPGA_xst_integration_interval_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_integration_interval_RW"], datatype=numpy.double, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_integration_interval_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_integration_interval_R"], datatype=numpy.double, dims=(N_pn,))
+    FPGA_xst_offload_enable_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_offload_enable_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_enable_R"], datatype=bool, dims=(N_pn,))
+    FPGA_xst_offload_hdr_eth_destination_mac_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_offload_hdr_eth_destination_mac_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_eth_destination_mac_R"], datatype=str, dims=(N_pn,))
+    FPGA_xst_offload_hdr_ip_destination_address_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_ip_destination_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_offload_hdr_ip_destination_address_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_ip_destination_address_R"], datatype=str, dims=(N_pn,))
+    FPGA_xst_offload_hdr_udp_destination_port_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_offload_hdr_udp_destination_port_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_pn,))
+    FPGA_xst_offload_bsn_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
+    FPGA_xst_processing_enable_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_processing_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_processing_enable_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_processing_enable_R"], datatype=bool, dims=(N_pn,))
+    FPGA_xst_subband_select_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_subband_select_RW"], datatype=numpy.uint32, dims=(MAX_PARALLEL_SUBBANDS,N_pn), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_subband_select_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_subband_select_R"], datatype=numpy.uint32, dims=(MAX_PARALLEL_SUBBANDS,N_pn))
+
+    FPGA_xst_offload_nof_crosslets_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_nof_crosslets_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_offload_nof_crosslets_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_nof_crosslets_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_xst_ring_nof_transport_hops_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_nof_transport_hops_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_ring_nof_transport_hops_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_nof_transport_hops_R"], datatype=numpy.uint32, dims=(N_pn,))
+
+    FPGA_xst_offload_nof_packets_R = AttributeWrapper(comms_annotation=["FPGA_xst_offload_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_xst_offload_nof_valid_R = AttributeWrapper(comms_annotation=["FPGA_xst_offload_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,))
+
+    FPGA_xst_ring_rx_clear_total_counts_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_clear_total_counts_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_ring_rx_clear_total_counts_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_clear_total_counts_R"], datatype=bool, dims=(N_pn,))
+    FPGA_xst_rx_align_stream_enable_RW = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_stream_enable_RW"], datatype=bool, dims=(N_pn,P_sq), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_rx_align_stream_enable_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_stream_enable_R"], datatype=bool, dims=(N_pn,P_sq))
+    FPGA_xst_ring_rx_total_nof_packets_received_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_packets_received_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_xst_ring_rx_total_nof_packets_discarded_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_packets_discarded_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_xst_ring_rx_total_nof_sync_received_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_sync_received_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_xst_ring_rx_total_nof_sync_discarded_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_sync_discarded_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_xst_ring_rx_bsn_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_bsn_R"], datatype=numpy.int64, dims=(N_pn, N_pn))
+    FPGA_xst_ring_rx_nof_packets_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_nof_packets_R"], datatype=numpy.int32, dims=(N_pn, N_pn))
+    FPGA_xst_ring_rx_nof_valid_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_nof_valid_R"], datatype=numpy.int32, dims=(N_pn, N_pn))
+    FPGA_xst_ring_rx_latency_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_latency_R"], datatype=numpy.int32, dims=(N_pn, N_pn))
+    FPGA_xst_rx_align_bsn_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_bsn_R"], datatype=numpy.int64, dims=(N_pn,P_sq))
+    FPGA_xst_rx_align_nof_packets_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,P_sq))
+    FPGA_xst_rx_align_nof_valid_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,P_sq))
+    FPGA_xst_rx_align_latency_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_latency_R"], datatype=numpy.int32, dims=(N_pn,P_sq))
+    FPGA_xst_rx_align_nof_replaced_packets_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_nof_replaced_packets_R"], datatype=numpy.int32, dims=(N_pn,P_sq))
+    FPGA_xst_aligned_bsn_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
+    FPGA_xst_aligned_nof_packets_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_xst_aligned_nof_valid_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_xst_aligned_latency_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_latency_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_xst_ring_tx_bsn_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_bsn_R"], datatype=numpy.int64, dims=(N_pn,N_pn))
+    FPGA_xst_ring_tx_nof_packets_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,N_pn))
+    FPGA_xst_ring_tx_nof_valid_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,N_pn))
+    FPGA_xst_ring_tx_latency_R = AttributeWrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_latency_R"], datatype=numpy.int32, dims=(N_pn,N_pn))
 
     # number of packets with valid payloads
-    nof_valid_payloads_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(N_pn,), datatype=numpy.uint64)
+    nof_valid_payloads_R    = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(N_pn,), datatype=numpy.uint64)
     # number of packets with invalid payloads
-    nof_payload_errors_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(N_pn,), datatype=numpy.uint64)
+    nof_payload_errors_R    = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(N_pn,), datatype=numpy.uint64)
     # latest XSTs
-    xst_blocks_R            = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_blocks", "reshape": True}, dims=(MAX_PARALLEL_SUBBANDS, MAX_BLOCKS, BLOCK_LENGTH, BLOCK_LENGTH, VALUES_PER_COMPLEX), datatype=numpy.int64)
+    xst_blocks_R            = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_blocks", "reshape": True}, dims=(MAX_PARALLEL_SUBBANDS, MAX_BLOCKS, BLOCK_LENGTH, BLOCK_LENGTH, VALUES_PER_COMPLEX), datatype=numpy.int64)
     # whether the values in the block are conjugated and transposed
-    xst_conjugated_R        = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_conjugated", "reshape": True}, dims=(MAX_PARALLEL_SUBBANDS, MAX_BLOCKS), datatype=bool)
+    xst_conjugated_R        = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_conjugated", "reshape": True}, dims=(MAX_PARALLEL_SUBBANDS, MAX_BLOCKS), datatype=bool)
     # reported timestamp for each subband in the latest XSTs
-    xst_timestamp_R         = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_timestamps"}, dims=(MAX_PARALLEL_SUBBANDS,), datatype=numpy.uint64)
+    xst_timestamp_R         = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_timestamps"}, dims=(MAX_PARALLEL_SUBBANDS,), datatype=numpy.uint64)
     # which subband the XSTs describe
-    xst_subbands_R          = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_subbands"}, dims=(MAX_PARALLEL_SUBBANDS,), datatype=numpy.uint16)
+    xst_subbands_R          = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_subbands"}, dims=(MAX_PARALLEL_SUBBANDS,), datatype=numpy.uint16)
     # integration interval for each subband in the latest XSTs
-    xst_integration_interval_R  = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_integration_intervals"}, dims=(MAX_PARALLEL_SUBBANDS,), datatype=numpy.float32)
+    xst_integration_interval_R  = AttributeWrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_integration_intervals"}, dims=(MAX_PARALLEL_SUBBANDS,), datatype=numpy.float32)
 
     # xst_R, but as a matrix of subband x (input x input)
     xst_real_R              = attribute(max_dim_x=MAX_INPUTS * MAX_INPUTS, max_dim_y=MAX_PARALLEL_SUBBANDS, dtype=((numpy.float32,),))
diff --git a/tangostationcontrol/tangostationcontrol/devices/snmp_device.py b/tangostationcontrol/tangostationcontrol/devices/snmp_device.py
index 15dbf2d24691f8b97e1d51cfe8c827ade4532930..f400d0cf99e933b7a2ab2d62c614d086300c278d 100644
--- a/tangostationcontrol/tangostationcontrol/devices/snmp_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/snmp_device.py
@@ -8,14 +8,14 @@
 """
 
 # Additional import
-from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.devices.lofar_device import LOFARDevice
 from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
 
 from tango.server import device_property
 import os
 
 import logging
-from tangostationcontrol.clients.snmp_client import SNMP_client, mib_loader
+from tangostationcontrol.clients.snmp_client import SNMPClient, MIBLoader
 
 import pkg_resources
 
@@ -25,11 +25,11 @@ debug.setLogger(debug.Debug('searcher', "compiler", "borrower", "reader"))
 
 logger = logging.getLogger()
 
-__all__ = ["snmp_device"]
+__all__ = ["SNMPDevice"]
 
 
 @device_logging_to_python()
-class snmp_device(lofar_device):
+class SNMPDevice(LOFARDevice):
     # -----------------
     # Device Properties
     # -----------------
@@ -62,7 +62,7 @@ class snmp_device(lofar_device):
     def configure_for_initialise(self):
 
         # set up the SNMP client
-        self.snmp_manager = SNMP_client(self.SNMP_community, self.SNMP_host, self.SNMP_timeout, self.SNMP_version, self.Fault, self)
+        self.snmp_manager = SNMPClient(self.SNMP_community, self.SNMP_host, self.SNMP_timeout, self.SNMP_version, self.Fault, self)
 
         # map an access helper class
         for i in self.attr_list():
@@ -94,8 +94,8 @@ class snmp_device(lofar_device):
     def init_device(self):
         super().init_device()
 
-        # create the mib_loader and set the mib path
-        self.loader = mib_loader(self.get_mib_dir())
+        # create the MIBLoader and set the mib path
+        self.loader = MIBLoader(self.get_mib_dir())
 
         for i in self.attr_list():
             try:
diff --git a/tangostationcontrol/tangostationcontrol/devices/temperature_manager.py b/tangostationcontrol/tangostationcontrol/devices/temperature_manager.py
index 8947e440364ac38d6da1fdd7ef5182018c91de9b..b725a9d4d315abdf97a863515ed91325994b4417 100644
--- a/tangostationcontrol/tangostationcontrol/devices/temperature_manager.py
+++ b/tangostationcontrol/tangostationcontrol/devices/temperature_manager.py
@@ -6,17 +6,17 @@
 """ overtemperature managing Device Server for LOFAR2.0
 
 """
+import numpy as np
+
+from tango import Util, DeviceProxy, AttributeInfoEx, AttrDataFormat, EventType, DevSource, DebugIt
+from tango.server import attribute, device_property
+from tango.server import command
 
 # Additional import
-from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.constants import DEFAULT_POLLING_PERIOD
-from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
-
-from tango.server import command
-from tango import Util, DeviceProxy, AttributeInfoEx, AttrDataFormat, EventType, DevSource, DebugIt
-from tango.server import attribute, device_property
-import numpy as np
+from tangostationcontrol.devices.lofar_device import LOFARDevice
 
 import logging
 logger = logging.getLogger()
@@ -24,7 +24,7 @@ logger = logging.getLogger()
 __all__ = ["TemperatureManager", "main"]
 
 
-class attr_info:
+class AttrInfo:
     def __init__(self, attr : AttributeInfoEx, subscription_id, proxy):
         self.attr_name = attr.name
         self.subscription_id = subscription_id
@@ -50,7 +50,7 @@ class attr_info:
 
 
 @device_logging_to_python()
-class TemperatureManager(lofar_device):
+class TemperatureManager(LOFARDevice):
     # -----------------
     # Device Properties
     # -----------------
@@ -105,7 +105,7 @@ class TemperatureManager(lofar_device):
 
             # store some info about the attribute
             atr_cfg = proxy.get_attribute_config(attribute_name)
-            self.temp_error_attrs[f"{proxy.name().lower()}/{attribute_name.lower()}"] = (attr_info(atr_cfg, subscription_id, proxy))
+            self.temp_error_attrs[f"{proxy.name().lower()}/{attribute_name.lower()}"] = (AttrInfo(atr_cfg, subscription_id, proxy))
 
         super().configure_for_initialise()
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/tilebeam.py b/tangostationcontrol/tangostationcontrol/devices/tilebeam.py
index c5442354f3ba06b46d8c0bc62f87f1fccb4adb34..ba399c1c7d07f4480e56e4db523a3d5afaa369c2 100644
--- a/tangostationcontrol/tangostationcontrol/devices/tilebeam.py
+++ b/tangostationcontrol/tangostationcontrol/devices/tilebeam.py
@@ -14,11 +14,11 @@ from tango import DeviceProxy, DevSource
 from tango import Util
 
 # Additional import
+from tangostationcontrol.beam.delays import Delays
+from tangostationcontrol.common.constants import N_xyz, N_elements, N_pol
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
-from tangostationcontrol.common.constants import N_xyz, N_elements, N_pol
-from tangostationcontrol.beam.delays import Delays
-from tangostationcontrol.devices.beam_device import beam_device
+from tangostationcontrol.devices.beam_device import BeamDevice
 from tangostationcontrol.devices.device_decorators import TimeIt
 
 import logging
@@ -27,8 +27,9 @@ logger = logging.getLogger()
 
 __all__ = ["TileBeam", "main"]
 
+
 @device_logging_to_python()
-class TileBeam(beam_device):
+class TileBeam(BeamDevice):
     """ Tracks a Tile Beam for all tiles in a single AntennaField. """
 
     # -----------------
diff --git a/tangostationcontrol/tangostationcontrol/devices/unb2.py b/tangostationcontrol/tangostationcontrol/devices/unb2.py
index 28716a92e666d48bb0780340e1f243f21e5b765e..08a316ba9f034dc5ccada13a9c7078a1e31bbeb7 100644
--- a/tangostationcontrol/tangostationcontrol/devices/unb2.py
+++ b/tangostationcontrol/tangostationcontrol/devices/unb2.py
@@ -16,21 +16,20 @@ from tango.server import command, attribute, device_property
 from tango import AttrWriteType, DebugIt
 # Additional import
 
-from tangostationcontrol.common.entrypoint import entry
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
 from tangostationcontrol.common.constants import N_unb, N_fpga, N_ddr, N_qsfp, DEFAULT_POLLING_PERIOD
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
-from tangostationcontrol.devices.opcua_device import opcua_device
+from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
 from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES
 from tangostationcontrol.devices.device_decorators import only_in_states
+from tangostationcontrol.devices.opcua_device import OPCUADevice
 
 import numpy
 
 __all__ = ["UNB2", "main"]
 
 @device_logging_to_python()
-class UNB2(opcua_device):
-
+class UNB2(OPCUADevice):
     # -----------------
     # Device Properties
     # -----------------
@@ -65,60 +64,60 @@ class UNB2(opcua_device):
         'UNB2TR_monitor_rate_RW'
     ]
 
-    UNB2TR_I2C_bus_DDR4_error_R  = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_DDR4_error_R"], datatype=numpy.int64, dims=(N_unb, N_fpga))
-    UNB2TR_I2C_bus_error_R       = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_error_R"    ], datatype=numpy.int64, dims=(N_unb,))
-    UNB2TR_I2C_bus_FPGA_PS_error_R = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_FPGA_PS_error_R"], datatype=numpy.int64, dims=(N_unb, N_fpga))
-    UNB2TR_I2C_bus_PS_error_R    = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_PS_error_R" ], datatype=numpy.int64, dims=(N_unb,))
-    UNB2TR_I2C_bus_QSFP_error_R  = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_QSFP_error_R"], datatype=numpy.int64, dims=(N_unb, N_qsfp))
-    UNB2TR_monitor_rate_RW       = attribute_wrapper(comms_annotation=["UNB2TR_monitor_rate_RW"    ],datatype=numpy.int64  , access=AttrWriteType.READ_WRITE)
-    UNB2TR_translator_busy_R     = attribute_wrapper(comms_annotation=["UNB2TR_translator_busy_R"  ],datatype=bool)
-    UNB2_DC_DC_48V_12V_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_IOUT_R" ], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_DC_DC_48V_12V_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_TEMP_R" ], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_DC_DC_48V_12V_VIN_R     = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_VIN_R"  ], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_DC_DC_48V_12V_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_VOUT_R" ], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_FPGA_DDR4_SLOT_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_DDR4_SLOT_TEMP_R"], datatype=numpy.float64, dims=(N_unb, N_fpga * N_ddr))
-    UNB2_FPGA_POL_CORE_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_IOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_CORE_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_TEMP_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_CORE_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_VOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_ERAM_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_IOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_ERAM_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_TEMP_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_ERAM_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_VOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_HGXB_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_IOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_HGXB_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_TEMP_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_HGXB_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_VOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_PGM_IOUT_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_IOUT_R"  ], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_PGM_TEMP_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_TEMP_R"  ], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_PGM_VOUT_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_VOUT_R"  ], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_RXGXB_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_IOUT_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_RXGXB_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_TEMP_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_RXGXB_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_VOUT_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_TXGXB_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_IOUT_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_TXGXB_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_TEMP_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_POL_TXGXB_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_VOUT_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
-    UNB2_FPGA_QSFP_CAGE_LOS_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_LOS_R" ], datatype=numpy.int64, dims=(N_unb, N_qsfp))
-    UNB2_FPGA_QSFP_CAGE_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_TEMP_R"], datatype=numpy.float64, dims=(N_unb, N_qsfp))
-    UNB2_Front_Panel_LED_colour_R = attribute_wrapper(comms_annotation=["UNB2_Front_Panel_LED_colour_R"], datatype=numpy.int64, dims=(N_unb,))
-    UNB2_Front_Panel_LED_colour_RW = attribute_wrapper(comms_annotation=["UNB2_Front_Panel_LED_colour_RW"], datatype=numpy.int64, dims=(N_unb,), access=AttrWriteType.READ_WRITE)
-    UNB2_mask_RW                 = attribute_wrapper(comms_annotation=["UNB2_mask_RW"              ], datatype=bool, dims=(N_unb,), access=AttrWriteType.READ_WRITE)
-    UNB2_PCB_ID_R                = attribute_wrapper(comms_annotation=["UNB2_PCB_ID_R"             ], datatype=numpy.int64, dims=(N_unb,))
-    UNB2_PCB_number_R            = attribute_wrapper(comms_annotation=["UNB2_PCB_number_R"         ], datatype=str, dims=(N_unb,))
-    UNB2_PCB_version_R           = attribute_wrapper(comms_annotation=["UNB2_PCB_version_R"        ], datatype=str, dims=(N_unb,))
-    UNB2_POL_CLOCK_IOUT_R        = attribute_wrapper(comms_annotation=["UNB2_POL_CLOCK_IOUT_R"     ], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_CLOCK_TEMP_R        = attribute_wrapper(comms_annotation=["UNB2_POL_CLOCK_TEMP_R"     ], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_CLOCK_VOUT_R        = attribute_wrapper(comms_annotation=["UNB2_POL_CLOCK_VOUT_R"     ], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_QSFP_N01_IOUT_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N01_IOUT_R"  ], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_QSFP_N01_TEMP_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N01_TEMP_R"  ], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_QSFP_N01_VOUT_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N01_VOUT_R"  ], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_QSFP_N23_IOUT_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N23_IOUT_R"  ], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_QSFP_N23_TEMP_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N23_TEMP_R"  ], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_QSFP_N23_VOUT_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N23_VOUT_R"  ], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_SWITCH_1V2_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_1V2_IOUT_R"], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_SWITCH_1V2_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_1V2_TEMP_R"], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_SWITCH_1V2_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_1V2_VOUT_R"], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_SWITCH_PHY_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_IOUT_R"], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_SWITCH_PHY_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_TEMP_R"], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_POL_SWITCH_PHY_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_VOUT_R"], datatype=numpy.float64, dims=(N_unb,))
-    UNB2_PWR_on_R                = attribute_wrapper(comms_annotation=["UNB2_PWR_on_R"             ], datatype=bool, dims=(N_unb,))
+    UNB2TR_I2C_bus_DDR4_error_R  = AttributeWrapper(comms_annotation=["UNB2TR_I2C_bus_DDR4_error_R"], datatype=numpy.int64, dims=(N_unb, N_fpga))
+    UNB2TR_I2C_bus_error_R       = AttributeWrapper(comms_annotation=["UNB2TR_I2C_bus_error_R"    ], datatype=numpy.int64, dims=(N_unb,))
+    UNB2TR_I2C_bus_FPGA_PS_error_R = AttributeWrapper(comms_annotation=["UNB2TR_I2C_bus_FPGA_PS_error_R"], datatype=numpy.int64, dims=(N_unb, N_fpga))
+    UNB2TR_I2C_bus_PS_error_R    = AttributeWrapper(comms_annotation=["UNB2TR_I2C_bus_PS_error_R" ], datatype=numpy.int64, dims=(N_unb,))
+    UNB2TR_I2C_bus_QSFP_error_R  = AttributeWrapper(comms_annotation=["UNB2TR_I2C_bus_QSFP_error_R"], datatype=numpy.int64, dims=(N_unb, N_qsfp))
+    UNB2TR_monitor_rate_RW       = AttributeWrapper(comms_annotation=["UNB2TR_monitor_rate_RW"    ],datatype=numpy.int64  , access=AttrWriteType.READ_WRITE)
+    UNB2TR_translator_busy_R     = AttributeWrapper(comms_annotation=["UNB2TR_translator_busy_R"  ],datatype=bool)
+    UNB2_DC_DC_48V_12V_IOUT_R    = AttributeWrapper(comms_annotation=["UNB2_DC_DC_48V_12V_IOUT_R" ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_DC_DC_48V_12V_TEMP_R    = AttributeWrapper(comms_annotation=["UNB2_DC_DC_48V_12V_TEMP_R" ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_DC_DC_48V_12V_VIN_R     = AttributeWrapper(comms_annotation=["UNB2_DC_DC_48V_12V_VIN_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_DC_DC_48V_12V_VOUT_R    = AttributeWrapper(comms_annotation=["UNB2_DC_DC_48V_12V_VOUT_R" ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_FPGA_DDR4_SLOT_TEMP_R   = AttributeWrapper(comms_annotation=["UNB2_FPGA_DDR4_SLOT_TEMP_R"], datatype=numpy.float64, dims=(N_unb, N_fpga * N_ddr))
+    UNB2_FPGA_POL_CORE_IOUT_R    = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_CORE_IOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_CORE_TEMP_R    = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_CORE_TEMP_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_CORE_VOUT_R    = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_CORE_VOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_ERAM_IOUT_R    = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_IOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_ERAM_TEMP_R    = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_TEMP_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_ERAM_VOUT_R    = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_VOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_HGXB_IOUT_R    = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_IOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_HGXB_TEMP_R    = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_TEMP_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_HGXB_VOUT_R    = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_VOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_PGM_IOUT_R     = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_PGM_IOUT_R"  ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_PGM_TEMP_R     = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_PGM_TEMP_R"  ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_PGM_VOUT_R     = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_PGM_VOUT_R"  ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_RXGXB_IOUT_R   = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_IOUT_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_RXGXB_TEMP_R   = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_TEMP_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_RXGXB_VOUT_R   = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_VOUT_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_TXGXB_IOUT_R   = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_IOUT_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_TXGXB_TEMP_R   = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_TEMP_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_TXGXB_VOUT_R   = AttributeWrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_VOUT_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_QSFP_CAGE_LOS_R    = AttributeWrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_LOS_R" ], datatype=numpy.int64, dims=(N_unb, N_qsfp))
+    UNB2_FPGA_QSFP_CAGE_TEMP_R   = AttributeWrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_TEMP_R"], datatype=numpy.float64, dims=(N_unb, N_qsfp))
+    UNB2_Front_Panel_LED_colour_R = AttributeWrapper(comms_annotation=["UNB2_Front_Panel_LED_colour_R"], datatype=numpy.int64, dims=(N_unb,))
+    UNB2_Front_Panel_LED_colour_RW = AttributeWrapper(comms_annotation=["UNB2_Front_Panel_LED_colour_RW"], datatype=numpy.int64, dims=(N_unb,), access=AttrWriteType.READ_WRITE)
+    UNB2_mask_RW                 = AttributeWrapper(comms_annotation=["UNB2_mask_RW"              ], datatype=bool, dims=(N_unb,), access=AttrWriteType.READ_WRITE)
+    UNB2_PCB_ID_R                = AttributeWrapper(comms_annotation=["UNB2_PCB_ID_R"             ], datatype=numpy.int64, dims=(N_unb,))
+    UNB2_PCB_number_R            = AttributeWrapper(comms_annotation=["UNB2_PCB_number_R"         ], datatype=str, dims=(N_unb,))
+    UNB2_PCB_version_R           = AttributeWrapper(comms_annotation=["UNB2_PCB_version_R"        ], datatype=str, dims=(N_unb,))
+    UNB2_POL_CLOCK_IOUT_R        = AttributeWrapper(comms_annotation=["UNB2_POL_CLOCK_IOUT_R"     ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_CLOCK_TEMP_R        = AttributeWrapper(comms_annotation=["UNB2_POL_CLOCK_TEMP_R"     ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_CLOCK_VOUT_R        = AttributeWrapper(comms_annotation=["UNB2_POL_CLOCK_VOUT_R"     ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_QSFP_N01_IOUT_R     = AttributeWrapper(comms_annotation=["UNB2_POL_QSFP_N01_IOUT_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_QSFP_N01_TEMP_R     = AttributeWrapper(comms_annotation=["UNB2_POL_QSFP_N01_TEMP_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_QSFP_N01_VOUT_R     = AttributeWrapper(comms_annotation=["UNB2_POL_QSFP_N01_VOUT_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_QSFP_N23_IOUT_R     = AttributeWrapper(comms_annotation=["UNB2_POL_QSFP_N23_IOUT_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_QSFP_N23_TEMP_R     = AttributeWrapper(comms_annotation=["UNB2_POL_QSFP_N23_TEMP_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_QSFP_N23_VOUT_R     = AttributeWrapper(comms_annotation=["UNB2_POL_QSFP_N23_VOUT_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_SWITCH_1V2_IOUT_R   = AttributeWrapper(comms_annotation=["UNB2_POL_SWITCH_1V2_IOUT_R"], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_SWITCH_1V2_TEMP_R   = AttributeWrapper(comms_annotation=["UNB2_POL_SWITCH_1V2_TEMP_R"], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_SWITCH_1V2_VOUT_R   = AttributeWrapper(comms_annotation=["UNB2_POL_SWITCH_1V2_VOUT_R"], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_SWITCH_PHY_IOUT_R   = AttributeWrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_IOUT_R"], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_SWITCH_PHY_TEMP_R   = AttributeWrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_TEMP_R"], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_SWITCH_PHY_VOUT_R   = AttributeWrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_VOUT_R"], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_PWR_on_R                = AttributeWrapper(comms_annotation=["UNB2_PWR_on_R"             ], datatype=bool, dims=(N_unb,))
 
     # ----------
     # Summarising Attributes
diff --git a/tangostationcontrol/tangostationcontrol/examples/HW_device_template.py b/tangostationcontrol/tangostationcontrol/examples/HW_device_template.py
index f7994ec1fea9892a3ae2ab44b57ff87a2b2f1958..de311503cbec99264e72178884c5d0e458d1ac3c 100644
--- a/tangostationcontrol/tangostationcontrol/examples/HW_device_template.py
+++ b/tangostationcontrol/tangostationcontrol/examples/HW_device_template.py
@@ -13,17 +13,17 @@
 from tango.server import run
 # Additional import
 
-from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.devices.lofar_device import LOFARDevice
 
 import logging
 logger = logging.getLogger()
 
-__all__ = ["HW_dev"]
+__all__ = ["HWDev"]
 
 
-class HW_dev(lofar_device):
+class HWDev(LOFARDevice):
     """
-    This class is the minimal (read empty) implementation of a class using 'lofar_device'
+    This class is the minimal (read empty) implementation of a class using 'LOFARDevice'
     """
 
     # ----------
@@ -32,7 +32,7 @@ class HW_dev(lofar_device):
     """
     attribute wrapper objects can be declared here. All attribute wrapper objects will get automatically put in a list (attr_list) for easy access
 
-    example = attribute_wrapper(comms_annotation="this is an example", datatype=numpy.double, dims=(8, 2), access=AttrWriteType.READ_WRITE)
+    example = AttributeWrapper(comms_annotation="this is an example", datatype=numpy.double, dims=(8, 2), access=AttrWriteType.READ_WRITE)
     ...
 
     """
@@ -83,4 +83,4 @@ class HW_dev(lofar_device):
 # ----------
 def main(args=None, **kwargs):
     """Main function of the hardware device module."""
-    return run((HW_dev,), args=args, **kwargs)
+    return run((HWDev,), args=args, **kwargs)
diff --git a/tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_client.py b/tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_client.py
index a31fdce9267413305663e2647e55367bddc77896..34a5ec1c053d08633fc3b5e0aa2c9a2b6465e8f7 100644
--- a/tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_client.py
+++ b/tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_client.py
@@ -5,7 +5,7 @@ import numpy
 import logging
 logger = logging.getLogger()
 
-__all__ = ["ini_client"]
+__all__ = ["IniClient"]
 
 
 NUMPY_TO_INI_DICT = {
@@ -32,7 +32,7 @@ INI_TO_NUMPY_DICT = {
 }
 
 
-class ini_client(CommClient):
+class IniClient(CommClient):
     """
     this class provides an example implementation of a comms_client.
     Durirng initialisation it creates a correctly shaped zero filled value. on read that value is returned and on write its modified.
@@ -96,7 +96,7 @@ class ini_client(CommClient):
 
     def _setup_value_conversion(self, attribute):
         """
-        gives the client access to the attribute_wrapper object in order to access all
+        gives the client access to the AttributeWrapper object in order to access all
         necessary data such as dimensionality and data type
         """
 
@@ -148,7 +148,7 @@ class ini_client(CommClient):
         # process the comms_annotation
         section, name = self._setup_annotation(annotation)
 
-        # get all the necessary data to set up the read/write functions from the attribute_wrapper
+        # get all the necessary data to set up the read/write functions from the AttributeWrapper
         dim_y, dim_x, dtype = self._setup_value_conversion(attribute)
 
         # configure and return the read/write functions
diff --git a/tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_device.py b/tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_device.py
index b49997f685d941e1a10c88bd2025f76396d693d4..e9d7f228ae308b729cfcdcbb7cfdb64863fe7476 100644
--- a/tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_device.py
+++ b/tangostationcontrol/tangostationcontrol/examples/load_from_disk/ini_device.py
@@ -17,15 +17,15 @@ import configparser
 import numpy
 
 # Additional import
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
-from tangostationcontrol.devices.lofar_device import lofar_device
-from tangostationcontrol.examples.load_from_disk.ini_client import ini_client
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
+from tangostationcontrol.devices.lofar_device import LOFARDevice
+from tangostationcontrol.examples.load_from_disk.ini_client import IniClient
 
 import logging
 logger = logging.getLogger()
 
 
-__all__ = ["ini_device"]
+__all__ = ["IniDevice"]
 
 
 def write_ini_file(filename):
@@ -54,9 +54,9 @@ def write_ini_file(filename):
 
 
 
-class ini_device(lofar_device):
+class IniDevice(LOFARDevice):
     """
-    This class is the minimal (read empty) implementation of a class using 'lofar_device'
+    This class is the minimal (read empty) implementation of a class using 'LOFARDevice'
     """
 
     # ----------
@@ -65,36 +65,36 @@ class ini_device(lofar_device):
     """
     attribute wrapper objects can be declared here. All attribute wrapper objects will get automatically put in a list (attr_list) for easy access
 
-    example = attribute_wrapper(comms_annotation="this is an example", datatype=numpy.double, dims=(8, 2), access=AttrWriteType.READ_WRITE)
+    example = AttributeWrapper(comms_annotation="this is an example", datatype=numpy.double, dims=(8, 2), access=AttrWriteType.READ_WRITE)
     ...
 
     """
-    double_scalar_RW = attribute_wrapper(comms_annotation={"section": "scalar", "name": "double_scalar_RW"}, datatype=numpy.double, access=AttrWriteType.READ_WRITE)
-    double_scalar_R = attribute_wrapper(comms_annotation={"section": "scalar", "name": "double_scalar_R"}, datatype=numpy.double)
-    bool_scalar_RW = attribute_wrapper(comms_annotation={"section": "scalar", "name": "bool_scalar_RW"}, datatype=bool, access=AttrWriteType.READ_WRITE)
-    bool_scalar_R = attribute_wrapper(comms_annotation={"section": "scalar", "name": "bool_scalar_R"}, datatype=bool)
-    int_scalar_RW = attribute_wrapper(comms_annotation={"section": "scalar", "name": "int_scalar_RW"}, datatype=numpy.int64, access=AttrWriteType.READ_WRITE)
-    int_scalar_R = attribute_wrapper(comms_annotation={"section": "scalar", "name": "int_scalar_R"}, datatype=numpy.int64)
-    str_scalar_RW = attribute_wrapper(comms_annotation={"section": "scalar", "name": "str_scalar_RW"}, datatype=str, access=AttrWriteType.READ_WRITE)
-    str_scalar_R = attribute_wrapper(comms_annotation={"section": "scalar", "name": "str_scalar_R"}, datatype=str)
-
-    double_spectrum_RW = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "double_spectrum_RW"}, datatype=numpy.double, dims=(4,), access=AttrWriteType.READ_WRITE)
-    double_spectrum_R = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "double_spectrum_R"}, datatype=numpy.double, dims=(4,))
-    bool_spectrum_RW = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "bool_spectrum_RW"}, datatype=bool, dims=(4,), access=AttrWriteType.READ_WRITE)
-    bool_spectrum_R = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "bool_spectrum_R"}, datatype=bool, dims=(4,))
-    int_spectrum_RW = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "int_spectrum_RW"}, datatype=numpy.int64, dims=(4,), access=AttrWriteType.READ_WRITE)
-    int_spectrum_R = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "int_spectrum_R"}, datatype=numpy.int64, dims=(4,))
-    str_spectrum_RW = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "str_spectrum_RW"}, datatype=str, dims=(4,), access=AttrWriteType.READ_WRITE)
-    str_spectrum_R = attribute_wrapper(comms_annotation={"section": "spectrum", "name": "str_spectrum_R"}, datatype=str, dims=(4,))
-
-    double_image_RW = attribute_wrapper(comms_annotation={"section": "image", "name": "double_image_RW"}, datatype=numpy.double, dims=(3, 2), access=AttrWriteType.READ_WRITE)
-    double_image_R = attribute_wrapper(comms_annotation={"section": "image", "name": "double_image_R"}, datatype=numpy.double, dims=(3, 2))
-    bool_image_RW = attribute_wrapper(comms_annotation={"section": "image", "name": "bool_image_RW"}, datatype=bool, dims=(3, 2), access=AttrWriteType.READ_WRITE)
-    bool_image_R = attribute_wrapper(comms_annotation={"section": "image", "name": "bool_image_R"}, datatype=bool, dims=(3, 2))
-    int_image_RW = attribute_wrapper(comms_annotation={"section": "image", "name": "int_image_RW"}, datatype=numpy.int64, dims=(3, 2), access=AttrWriteType.READ_WRITE)
-    int_image_R = attribute_wrapper(comms_annotation={"section": "image", "name": "int_image_R"}, datatype=numpy.int64, dims=(3, 2))
-    str_image_RW = attribute_wrapper(comms_annotation={"section": "image", "name": "str_image_RW"}, datatype=str, dims=(3, 2), access=AttrWriteType.READ_WRITE)
-    str_image_R = attribute_wrapper(comms_annotation={"section": "image", "name": "str_image_R"}, datatype=str, dims=(3, 2))
+    double_scalar_RW = AttributeWrapper(comms_annotation={"section": "scalar", "name": "double_scalar_RW"}, datatype=numpy.double, access=AttrWriteType.READ_WRITE)
+    double_scalar_R = AttributeWrapper(comms_annotation={"section": "scalar", "name": "double_scalar_R"}, datatype=numpy.double)
+    bool_scalar_RW = AttributeWrapper(comms_annotation={"section": "scalar", "name": "bool_scalar_RW"}, datatype=bool, access=AttrWriteType.READ_WRITE)
+    bool_scalar_R = AttributeWrapper(comms_annotation={"section": "scalar", "name": "bool_scalar_R"}, datatype=bool)
+    int_scalar_RW = AttributeWrapper(comms_annotation={"section": "scalar", "name": "int_scalar_RW"}, datatype=numpy.int64, access=AttrWriteType.READ_WRITE)
+    int_scalar_R = AttributeWrapper(comms_annotation={"section": "scalar", "name": "int_scalar_R"}, datatype=numpy.int64)
+    str_scalar_RW = AttributeWrapper(comms_annotation={"section": "scalar", "name": "str_scalar_RW"}, datatype=str, access=AttrWriteType.READ_WRITE)
+    str_scalar_R = AttributeWrapper(comms_annotation={"section": "scalar", "name": "str_scalar_R"}, datatype=str)
+
+    double_spectrum_RW = AttributeWrapper(comms_annotation={"section": "spectrum", "name": "double_spectrum_RW"}, datatype=numpy.double, dims=(4,), access=AttrWriteType.READ_WRITE)
+    double_spectrum_R = AttributeWrapper(comms_annotation={"section": "spectrum", "name": "double_spectrum_R"}, datatype=numpy.double, dims=(4,))
+    bool_spectrum_RW = AttributeWrapper(comms_annotation={"section": "spectrum", "name": "bool_spectrum_RW"}, datatype=bool, dims=(4,), access=AttrWriteType.READ_WRITE)
+    bool_spectrum_R = AttributeWrapper(comms_annotation={"section": "spectrum", "name": "bool_spectrum_R"}, datatype=bool, dims=(4,))
+    int_spectrum_RW = AttributeWrapper(comms_annotation={"section": "spectrum", "name": "int_spectrum_RW"}, datatype=numpy.int64, dims=(4,), access=AttrWriteType.READ_WRITE)
+    int_spectrum_R = AttributeWrapper(comms_annotation={"section": "spectrum", "name": "int_spectrum_R"}, datatype=numpy.int64, dims=(4,))
+    str_spectrum_RW = AttributeWrapper(comms_annotation={"section": "spectrum", "name": "str_spectrum_RW"}, datatype=str, dims=(4,), access=AttrWriteType.READ_WRITE)
+    str_spectrum_R = AttributeWrapper(comms_annotation={"section": "spectrum", "name": "str_spectrum_R"}, datatype=str, dims=(4,))
+
+    double_image_RW = AttributeWrapper(comms_annotation={"section": "image", "name": "double_image_RW"}, datatype=numpy.double, dims=(3, 2), access=AttrWriteType.READ_WRITE)
+    double_image_R = AttributeWrapper(comms_annotation={"section": "image", "name": "double_image_R"}, datatype=numpy.double, dims=(3, 2))
+    bool_image_RW = AttributeWrapper(comms_annotation={"section": "image", "name": "bool_image_RW"}, datatype=bool, dims=(3, 2), access=AttrWriteType.READ_WRITE)
+    bool_image_R = AttributeWrapper(comms_annotation={"section": "image", "name": "bool_image_R"}, datatype=bool, dims=(3, 2))
+    int_image_RW = AttributeWrapper(comms_annotation={"section": "image", "name": "int_image_RW"}, datatype=numpy.int64, dims=(3, 2), access=AttrWriteType.READ_WRITE)
+    int_image_R = AttributeWrapper(comms_annotation={"section": "image", "name": "int_image_R"}, datatype=numpy.int64, dims=(3, 2))
+    str_image_RW = AttributeWrapper(comms_annotation={"section": "image", "name": "str_image_RW"}, datatype=str, dims=(3, 2), access=AttrWriteType.READ_WRITE)
+    str_image_R = AttributeWrapper(comms_annotation={"section": "image", "name": "str_image_R"}, datatype=str, dims=(3, 2))
 
     # --------
     # overloaded functions
@@ -104,7 +104,7 @@ class ini_device(lofar_device):
         """Initialises the attributes and properties of the Hardware."""
 
         # set up the OPC ua client
-        self.ini_client = ini_client("example.ini", self.Fault, self)
+        self.ini_client = IniClient("example.ini", self.Fault, self)
 
         # map an access helper class
         for i in self.attr_list():
@@ -126,4 +126,4 @@ def main(args=None, **kwargs):
     write_ini_file("example.ini")
 
     """Main function of the hardware device module."""
-    return run((ini_device,), args=args, **kwargs)
+    return run((IniDevice,), args=args, **kwargs)
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/README.md b/tangostationcontrol/tangostationcontrol/integration_test/README.md
index c917ae188593bfd8539552072e149307414db166..828826aabde546948b10422ee64b50d4138f9e8d 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/README.md
+++ b/tangostationcontrol/tangostationcontrol/integration_test/README.md
@@ -34,7 +34,7 @@ These arguments and modules can also be passed at the level of the Makefile
 instead of through tox directly:
 
 ```shell
-make integration import.path.class.functionname`
+make integration default import.path.class.functionname`
 ```
 
 Since at each layer tests can be specified, the information amount selection
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/client/test_opcua_client_against_server.py b/tangostationcontrol/tangostationcontrol/integration_test/default/client/test_opcua_client_against_server.py
index e16ac79e1f991737910d689b6fdc406dce2a0e3d..090444cae29b140a8388fed6612ba603ba140ca0 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/default/client/test_opcua_client_against_server.py
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/client/test_opcua_client_against_server.py
@@ -85,12 +85,12 @@ class TestClientServer(base.IntegrationAsyncTestCase):
             await test_client.start()
 
             # setup the attribute
-            class attribute(object):
+            class Attribute(object):
                 dim_x = 1
                 dim_y = 0
                 datatype = numpy.double
 
-            prot_attr = await test_client.setup_protocol_attribute(["double_R"], attribute())
+            prot_attr = await test_client.setup_protocol_attribute(["double_R"], Attribute())
 
             # read it from the server
             self.assertEqual(42.0, await prot_attr.read_function())
@@ -105,12 +105,12 @@ class TestClientServer(base.IntegrationAsyncTestCase):
             await test_client.start()
 
             # setup the attribute
-            class attribute(object):
+            class Attribute(object):
                 dim_x = 1
                 dim_y = 0
                 datatype = numpy.double
 
-            prot_attr = await test_client.setup_protocol_attribute(["double_RW"], attribute())
+            prot_attr = await test_client.setup_protocol_attribute(["double_RW"], Attribute())
 
             # write it to the server and read it back to verify
             await prot_attr.write_function(123.0)
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/base.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/base.py
index 7a61a457e941da98c3695e91573a5a4424102db3..973bd3d8726e7b9300c7ee045898489ca9c4f8f7 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/base.py
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/base.py
@@ -9,7 +9,7 @@
 
 from tango._tango import DevState
 
-from tangostationcontrol.devices.opcua_device import opcua_device
+from tangostationcontrol.devices.opcua_device import OPCUADevice
 from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy
 from tangostationcontrol.integration_test import base
 
@@ -67,7 +67,7 @@ class AbstractTestBases:
         def test_device_missing_attributes(self):
             """Test if any attributes are missing from opcua devices"""
 
-            if isinstance(self.proxy, opcua_device):
+            if isinstance(self.proxy, OPCUADevice):
                 self.self.assertListEqual([], self.proxy.opcua_missing_attributes_R)
 
         def test_device_on(self):
diff --git a/tangostationcontrol/tangostationcontrol/statistics/reader.py b/tangostationcontrol/tangostationcontrol/statistics/reader.py
index b0b1ff4e6f2b7f67a14f8045c589dc7815d55232..fd5055868379d88b98718bd4bad79b5ef1375c78 100644
--- a/tangostationcontrol/tangostationcontrol/statistics/reader.py
+++ b/tangostationcontrol/tangostationcontrol/statistics/reader.py
@@ -34,7 +34,7 @@ def timeit(method):
     return timed
 
 
-class statistics_parser:
+class StatisticsParser:
     """
     This class goes through the file and creates a list of all statistics in the file it is given
     """
@@ -82,7 +82,7 @@ class statistics_parser:
             for group_key in hdf5_file.keys():
                 try:
                     # first get the statistic
-                    statistic = statistics_data(hdf5_file, group_key)
+                    statistic = StatisticsData(hdf5_file, group_key)
 
                     # extract the timestamp and convert to datetime
                     statistic_time = statistic.timestamp
@@ -148,7 +148,7 @@ class statistics_parser:
         return len(self.statistics)
 
 
-class statistics_data:
+class StatisticsData:
     """
     This class takes the file and the statistics name as its __init__ arguments and then stores the
     the datasets in them.
@@ -260,7 +260,7 @@ def setup_stat_parser():
     files, end_time, start_time = parse_arguments()
 
     # create the parser
-    stat_parser = statistics_parser()
+    stat_parser = StatisticsParser()
 
     # set the correct time ranges
     if end_time is not None:
diff --git a/tangostationcontrol/tangostationcontrol/statistics/receiver.py b/tangostationcontrol/tangostationcontrol/statistics/receiver.py
index b9c823c2a822cd4aee4a02bf6e921246e7dec471..943dbf5ef843a89843621b660078d16e7a845d9a 100644
--- a/tangostationcontrol/tangostationcontrol/statistics/receiver.py
+++ b/tangostationcontrol/tangostationcontrol/statistics/receiver.py
@@ -13,7 +13,7 @@ import socket
 from lofar_station_client.statistics.packet import StatisticsPacket
 
 
-class receiver:
+class Receiver:
     """ Reads data from a file descriptor. """
 
     HEADER_LENGTH = 32
@@ -59,7 +59,7 @@ class receiver:
         return data
 
 
-class tcp_receiver(receiver):
+class TCPReceiver(Receiver):
     def __init__(self, HOST, PORT):
         self.host = HOST
         self.port = PORT
@@ -81,7 +81,7 @@ class tcp_receiver(receiver):
         return True
 
 
-class file_receiver(receiver):
+class FileReceiver(Receiver):
     def __init__(self, filename):
         self.filename = filename
         self.fileno = os.open(filename, os.O_RDONLY)
diff --git a/tangostationcontrol/tangostationcontrol/statistics/udp_dev/udp_client.py b/tangostationcontrol/tangostationcontrol/statistics/udp_dev/udp_client.py
index 98a85d62d1d3e610ed747b49f5034eb1dc3afeec..270b24e667d4cb043f2a402229d086156c4b5218 100644
--- a/tangostationcontrol/tangostationcontrol/statistics/udp_dev/udp_client.py
+++ b/tangostationcontrol/tangostationcontrol/statistics/udp_dev/udp_client.py
@@ -5,7 +5,7 @@ from datetime import datetime
 import time
 
 
-class UDP_Client:
+class UDPClient:
 
     def __init__(self, server_ip:str, server_port:int):
         self.server_ip = server_ip
@@ -56,5 +56,5 @@ if __name__ == '__main__':
         print("Run like : python3 udp_client.py <server_ip> <server_port>")
         exit(1)
 
-    client = UDP_Client(server_ip,server_port)
+    client = UDPClient(server_ip,server_port)
     client.run()
diff --git a/tangostationcontrol/tangostationcontrol/statistics/udp_dev/udp_server.py b/tangostationcontrol/tangostationcontrol/statistics/udp_dev/udp_server.py
index 413633f34713ad24e6225fd086e98a9241970d12..8e7968dacc0a0ab5d577798d573ee2b4ed498000 100644
--- a/tangostationcontrol/tangostationcontrol/statistics/udp_dev/udp_server.py
+++ b/tangostationcontrol/tangostationcontrol/statistics/udp_dev/udp_server.py
@@ -3,7 +3,7 @@ import netifaces as ni
 from datetime import datetime
 
 
-class UDP_Server:
+class UDPServer:
 
     def __init__(self, ip:str, port:int, buffer_size:int = 8192):
         self.ip = ip
@@ -46,5 +46,5 @@ class UDP_Server:
 
 if __name__ == '__main__':
     local_ip = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
-    server = UDP_Server(local_ip,5600)
+    server = UDPServer(local_ip,5600)
     server.run()
diff --git a/tangostationcontrol/tangostationcontrol/statistics/udp_dev/udp_write_manager.py b/tangostationcontrol/tangostationcontrol/statistics/udp_dev/udp_write_manager.py
index 9ba412576d1ffdee1c7819467e2292286869079e..a5a20513e30b77af08b8dae4ab74d6c95001ec88 100644
--- a/tangostationcontrol/tangostationcontrol/statistics/udp_dev/udp_write_manager.py
+++ b/tangostationcontrol/tangostationcontrol/statistics/udp_dev/udp_write_manager.py
@@ -3,14 +3,14 @@ import time
 import os
 import h5py
 import numpy as np
-from statistics_writer.udp_dev import udp_server as udp
+from statistics.udp_dev.udp_server import UDPServer
 import netifaces as ni
 from packet import SSTPacket
 
-__all__ = ["Statistics_Writer"]
+__all__ = ["StatisticsWriter"]
 
 
-class Statistics_Writer:
+class StatisticsWriter:
 
     def __init__(self, new_file_time_interval):
 
@@ -19,7 +19,7 @@ class Statistics_Writer:
 
         # Define ip and port of the receiver
         self.local_ip = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
-        self.server = udp.UDP_Server(self.local_ip, 5600)
+        self.server = UDPServer(self.local_ip, 5600)
 
         # Create data directory if not exists
         try:
@@ -72,7 +72,7 @@ class Statistics_Writer:
 
 if __name__ == "__main__":
     # create a data dumper that creates a new file every 10s (for testing)
-    test = Statistics_Writer(new_file_time_interval=10)
+    test = StatisticsWriter(new_file_time_interval=10)
 
     # simple loop to write data every second
     while True:
diff --git a/tangostationcontrol/tangostationcontrol/statistics/writer/entry.py b/tangostationcontrol/tangostationcontrol/statistics/writer/entry.py
index 171db69eb0d5ff25c420a7c9bba3336d9268e50d..0159dda4aaa0f65b6bb06fca6ff7fd7b7b732d63 100644
--- a/tangostationcontrol/tangostationcontrol/statistics/writer/entry.py
+++ b/tangostationcontrol/tangostationcontrol/statistics/writer/entry.py
@@ -12,8 +12,8 @@ import time
 import sys
 from tango import DeviceProxy
 
-from tangostationcontrol.statistics.receiver import file_receiver
-from tangostationcontrol.statistics.receiver import tcp_receiver
+from tangostationcontrol.statistics.receiver import FileReceiver
+from tangostationcontrol.statistics.receiver import TCPReceiver
 from tangostationcontrol.statistics.writer.hdf5 import BstHdf5Writer
 from tangostationcontrol.statistics.writer.hdf5 import SstHdf5Writer
 from tangostationcontrol.statistics.writer.hdf5 import ParallelXstHdf5Writer
@@ -76,9 +76,9 @@ def _create_parser():
 def _create_receiver(filename, host, port):
     """ creates the TCP receiver that is given to the writer """
     if filename:
-        return file_receiver(filename)
+        return FileReceiver(filename)
     elif host and port:
-        return tcp_receiver(host, port)
+        return TCPReceiver(host, port)
     else:
         logger.fatal("Must provide either a host and port, or a file to receive input from")
         sys.exit(1)
diff --git a/tangostationcontrol/tangostationcontrol/test/beam/test_geo.py b/tangostationcontrol/tangostationcontrol/test/beam/test_geo.py
index 22def29f3a0ba17b627bd1e6308256f826bc1c9a..e3b8d726a67560e80ea73d963e4d80f8eddce848 100644
--- a/tangostationcontrol/tangostationcontrol/test/beam/test_geo.py
+++ b/tangostationcontrol/tangostationcontrol/test/beam/test_geo.py
@@ -13,7 +13,7 @@ from tangostationcontrol.test import base
 
 import numpy.testing
 
-class TestETRS_to_ITRF(base.TestCase):
+class TestETRSToITRF(base.TestCase):
     def test_convert_single_coordinate(self):
         """ Convert a single coordinate. """
         ETRS_coords = numpy.array([1.0, 1.0, 1.0])
@@ -42,7 +42,7 @@ class TestETRS_to_ITRF(base.TestCase):
 
         numpy.testing.assert_almost_equal(CS001_LBA_ITRF, LOFAR1_CS001_LBA_ITRF, decimal=1.5)
 
-class TestETRS_to_GEO(base.TestCase):
+class TestETRSToGEO(base.TestCase):
     def test_convert_single_coordinate(self):
         """ Convert a single coordinate. """
         ETRS_coords = numpy.array([1.0, 1.0, 1.0])
@@ -71,7 +71,7 @@ class TestETRS_to_GEO(base.TestCase):
 
         numpy.testing.assert_almost_equal(CS001_LBA_GEO, LOFAR1_CS001_LBA_GEO, decimal=3)
 
-class TestGEO_to_GEOHASH(base.TestCase):
+class TestGEOToGEOHASH(base.TestCase):
     def test_convert_single_coordinate(self):
         """ Convert a single coordinate. """
         GEO_coords = numpy.array([1.0, 1.0])
diff --git a/tangostationcontrol/tangostationcontrol/test/clients/test_attr_wrapper.py b/tangostationcontrol/tangostationcontrol/test/clients/test_attr_wrapper.py
index 218f34d73c85fe2eaf55ac68ae645bd329e8f114..8df95918abcb7cf6dd33d002ac5db60087008d57 100644
--- a/tangostationcontrol/tangostationcontrol/test/clients/test_attr_wrapper.py
+++ b/tangostationcontrol/tangostationcontrol/test/clients/test_attr_wrapper.py
@@ -10,9 +10,9 @@
 from tango import DevState, DevFailed, AttrWriteType
 
 # Internal imports
-from tangostationcontrol.test.clients.test_client import test_client
-from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
-from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.test.clients.test_client import TestClient
+from tangostationcontrol.clients.attribute_wrapper import AttributeWrapper
+from tangostationcontrol.devices.lofar_device import LOFARDevice
 import tangostationcontrol.devices.lofar_device
 
 # Test imports
@@ -34,7 +34,7 @@ STR_IMAGE_VAL = [['1','1'],['1','1'],['1','1']]
 
 def dev_init(device):
     device.set_state(DevState.INIT)
-    device.test_client = test_client(device.Fault)
+    device.test_client = TestClient(device.Fault)
     for i in device.attr_list():
         asyncio.run(i.async_set_comm_client(device, device.test_client))
     device.test_client.start()
@@ -46,254 +46,254 @@ class TestAttributeTypes(base.TestCase):
         self.deviceproxy_patch.start()
         self.addCleanup(self.deviceproxy_patch.stop)
 
-    class str_scalar_device(lofar_device):
-        scalar_R = attribute_wrapper(comms_annotation="str_scalar_R", datatype=str)
-        scalar_RW = attribute_wrapper(comms_annotation="str_scalar_RW", datatype=str, access=AttrWriteType.READ_WRITE)
+    class StrScalarDevice(LOFARDevice):
+        scalar_R = AttributeWrapper(comms_annotation="str_scalar_R", datatype=str)
+        scalar_RW = AttributeWrapper(comms_annotation="str_scalar_RW", datatype=str, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class bool_scalar_device(lofar_device):
-        scalar_R = attribute_wrapper(comms_annotation="bool_scalar_R", datatype=bool)
-        scalar_RW = attribute_wrapper(comms_annotation="bool_scalar_RW", datatype=bool, access=AttrWriteType.READ_WRITE)
+    class BoolScalarDevice(LOFARDevice):
+        scalar_R = AttributeWrapper(comms_annotation="bool_scalar_R", datatype=bool)
+        scalar_RW = AttributeWrapper(comms_annotation="bool_scalar_RW", datatype=bool, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class float32_scalar_device(lofar_device):
-        scalar_R = attribute_wrapper(comms_annotation="float32_scalar_R", datatype=numpy.float32)
-        scalar_RW = attribute_wrapper(comms_annotation="float32_scalar_RW", datatype=numpy.float32, access=AttrWriteType.READ_WRITE)
+    class Float32ScalarDevice(LOFARDevice):
+        scalar_R = AttributeWrapper(comms_annotation="float32_scalar_R", datatype=numpy.float32)
+        scalar_RW = AttributeWrapper(comms_annotation="float32_scalar_RW", datatype=numpy.float32, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class float64_scalar_device(lofar_device):
-        scalar_R = attribute_wrapper(comms_annotation="float64_scalar_R", datatype=numpy.float64)
-        scalar_RW = attribute_wrapper(comms_annotation="float64_scalar_RW", datatype=numpy.float64, access=AttrWriteType.READ_WRITE)
+    class Float64ScalarDevice(LOFARDevice):
+        scalar_R = AttributeWrapper(comms_annotation="float64_scalar_R", datatype=numpy.float64)
+        scalar_RW = AttributeWrapper(comms_annotation="float64_scalar_RW", datatype=numpy.float64, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class double_scalar_device(lofar_device):
-        scalar_R = attribute_wrapper(comms_annotation="double_scalar_R", datatype=numpy.double)
-        scalar_RW = attribute_wrapper(comms_annotation="double_scalar_RW", datatype=numpy.double, access=AttrWriteType.READ_WRITE)
+    class DoubleScalarDevice(LOFARDevice):
+        scalar_R = AttributeWrapper(comms_annotation="double_scalar_R", datatype=numpy.double)
+        scalar_RW = AttributeWrapper(comms_annotation="double_scalar_RW", datatype=numpy.double, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class uint8_scalar_device(lofar_device):
-        scalar_R = attribute_wrapper(comms_annotation="uint8_scalar_R", datatype=numpy.uint8)
-        scalar_RW = attribute_wrapper(comms_annotation="uint8_scalar_RW", datatype=numpy.uint8, access=AttrWriteType.READ_WRITE)
+    class Uint8ScalarDevice(LOFARDevice):
+        scalar_R = AttributeWrapper(comms_annotation="uint8_scalar_R", datatype=numpy.uint8)
+        scalar_RW = AttributeWrapper(comms_annotation="uint8_scalar_RW", datatype=numpy.uint8, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class uint16_scalar_device(lofar_device):
-        scalar_R = attribute_wrapper(comms_annotation="uint16_scalar_R", datatype=numpy.uint16)
-        scalar_RW = attribute_wrapper(comms_annotation="uint16_scalar_RW", datatype=numpy.uint16, access=AttrWriteType.READ_WRITE)
+    class Uint16ScalarDevice(LOFARDevice):
+        scalar_R = AttributeWrapper(comms_annotation="uint16_scalar_R", datatype=numpy.uint16)
+        scalar_RW = AttributeWrapper(comms_annotation="uint16_scalar_RW", datatype=numpy.uint16, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class uint32_scalar_device(lofar_device):
-        scalar_R = attribute_wrapper(comms_annotation="uint32_scalar_R", datatype=numpy.uint32)
-        scalar_RW = attribute_wrapper(comms_annotation="uint32_scalar_RW", datatype=numpy.uint32, access=AttrWriteType.READ_WRITE)
+    class Uint32ScalarDevice(LOFARDevice):
+        scalar_R = AttributeWrapper(comms_annotation="uint32_scalar_R", datatype=numpy.uint32)
+        scalar_RW = AttributeWrapper(comms_annotation="uint32_scalar_RW", datatype=numpy.uint32, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class uint64_scalar_device(lofar_device):
-        scalar_R = attribute_wrapper(comms_annotation="uint64_scalar_R", datatype=numpy.uint64)
-        scalar_RW = attribute_wrapper(comms_annotation="uint64_scalar_RW", datatype=numpy.uint64, access=AttrWriteType.READ_WRITE)
+    class Uint64ScalarDevice(LOFARDevice):
+        scalar_R = AttributeWrapper(comms_annotation="uint64_scalar_R", datatype=numpy.uint64)
+        scalar_RW = AttributeWrapper(comms_annotation="uint64_scalar_RW", datatype=numpy.uint64, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class int16_scalar_device(lofar_device):
-        scalar_R = attribute_wrapper(comms_annotation="int16_scalar_R", datatype=numpy.int16)
-        scalar_RW = attribute_wrapper(comms_annotation="int16_scalar_RW", datatype=numpy.int16, access=AttrWriteType.READ_WRITE)
+    class Int16ScalarDevice(LOFARDevice):
+        scalar_R = AttributeWrapper(comms_annotation="int16_scalar_R", datatype=numpy.int16)
+        scalar_RW = AttributeWrapper(comms_annotation="int16_scalar_RW", datatype=numpy.int16, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class int32_scalar_device(lofar_device):
-        scalar_R = attribute_wrapper(comms_annotation="int32_scalar_R", datatype=numpy.int32)
-        scalar_RW = attribute_wrapper(comms_annotation="int32_scalar_RW", datatype=numpy.int32, access=AttrWriteType.READ_WRITE)
+    class Int32ScalarDevice(LOFARDevice):
+        scalar_R = AttributeWrapper(comms_annotation="int32_scalar_R", datatype=numpy.int32)
+        scalar_RW = AttributeWrapper(comms_annotation="int32_scalar_RW", datatype=numpy.int32, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class int64_scalar_device(lofar_device):
-        scalar_R = attribute_wrapper(comms_annotation="int64_scalar_R", datatype=numpy.int64)
-        scalar_RW = attribute_wrapper(comms_annotation="int64_scalar_RW", datatype=numpy.int64, access=AttrWriteType.READ_WRITE)
+    class Int64ScalarDevice(LOFARDevice):
+        scalar_R = AttributeWrapper(comms_annotation="int64_scalar_R", datatype=numpy.int64)
+        scalar_RW = AttributeWrapper(comms_annotation="int64_scalar_RW", datatype=numpy.int64, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class str_spectrum_device(lofar_device):
-        spectrum_R = attribute_wrapper(comms_annotation="str_spectrum_R", datatype=str, dims=SPECTRUM_DIMS)
-        spectrum_RW = attribute_wrapper(comms_annotation="str_spectrum_RW", datatype=str, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
+    class StrSpectrumDevice(LOFARDevice):
+        spectrum_R = AttributeWrapper(comms_annotation="str_spectrum_R", datatype=str, dims=SPECTRUM_DIMS)
+        spectrum_RW = AttributeWrapper(comms_annotation="str_spectrum_RW", datatype=str, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class bool_spectrum_device(lofar_device):
-        spectrum_R = attribute_wrapper(comms_annotation="bool_spectrum_R", datatype=bool, dims=SPECTRUM_DIMS)
-        spectrum_RW = attribute_wrapper(comms_annotation="bool_spectrum_RW", datatype=bool, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
+    class BoolSpectrumDevice(LOFARDevice):
+        spectrum_R = AttributeWrapper(comms_annotation="bool_spectrum_R", datatype=bool, dims=SPECTRUM_DIMS)
+        spectrum_RW = AttributeWrapper(comms_annotation="bool_spectrum_RW", datatype=bool, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class float32_spectrum_device(lofar_device):
-        spectrum_R = attribute_wrapper(comms_annotation="float32_spectrum_R", datatype=numpy.float32, dims=SPECTRUM_DIMS)
-        spectrum_RW = attribute_wrapper(comms_annotation="float32_spectrum_RW", datatype=numpy.float32, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
+    class Float32SpectrumDevice(LOFARDevice):
+        spectrum_R = AttributeWrapper(comms_annotation="float32_spectrum_R", datatype=numpy.float32, dims=SPECTRUM_DIMS)
+        spectrum_RW = AttributeWrapper(comms_annotation="float32_spectrum_RW", datatype=numpy.float32, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class float64_spectrum_device(lofar_device):
-        spectrum_R = attribute_wrapper(comms_annotation="float64_spectrum_R", datatype=numpy.float64, dims=SPECTRUM_DIMS)
-        spectrum_RW = attribute_wrapper(comms_annotation="float64_spectrum_RW", datatype=numpy.float64, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
+    class Float64SpectrumDevice(LOFARDevice):
+        spectrum_R = AttributeWrapper(comms_annotation="float64_spectrum_R", datatype=numpy.float64, dims=SPECTRUM_DIMS)
+        spectrum_RW = AttributeWrapper(comms_annotation="float64_spectrum_RW", datatype=numpy.float64, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class double_spectrum_device(lofar_device):
-        spectrum_R = attribute_wrapper(comms_annotation="double_spectrum_R", datatype=numpy.double, dims=SPECTRUM_DIMS)
-        spectrum_RW = attribute_wrapper(comms_annotation="double_spectrum_RW", datatype=numpy.double, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
+    class DoubleSpectrumDevice(LOFARDevice):
+        spectrum_R = AttributeWrapper(comms_annotation="double_spectrum_R", datatype=numpy.double, dims=SPECTRUM_DIMS)
+        spectrum_RW = AttributeWrapper(comms_annotation="double_spectrum_RW", datatype=numpy.double, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class uint8_spectrum_device(lofar_device):
-        spectrum_R = attribute_wrapper(comms_annotation="uint8_spectrum_R", datatype=numpy.uint8, dims=SPECTRUM_DIMS)
-        spectrum_RW = attribute_wrapper(comms_annotation="uint8_spectrum_RW", datatype=numpy.uint8, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
+    class Uint8SpectrumDevice(LOFARDevice):
+        spectrum_R = AttributeWrapper(comms_annotation="uint8_spectrum_R", datatype=numpy.uint8, dims=SPECTRUM_DIMS)
+        spectrum_RW = AttributeWrapper(comms_annotation="uint8_spectrum_RW", datatype=numpy.uint8, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class uint16_spectrum_device(lofar_device):
-        spectrum_R = attribute_wrapper(comms_annotation="uint16_spectrum_R", datatype=numpy.uint16, dims=SPECTRUM_DIMS)
-        spectrum_RW = attribute_wrapper(comms_annotation="uint16_spectrum_RW", datatype=numpy.uint16, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
+    class Uint16SpectrumDevice(LOFARDevice):
+        spectrum_R = AttributeWrapper(comms_annotation="uint16_spectrum_R", datatype=numpy.uint16, dims=SPECTRUM_DIMS)
+        spectrum_RW = AttributeWrapper(comms_annotation="uint16_spectrum_RW", datatype=numpy.uint16, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class uint32_spectrum_device(lofar_device):
-        spectrum_R = attribute_wrapper(comms_annotation="uint32_spectrum_R", datatype=numpy.uint32, dims=SPECTRUM_DIMS)
-        spectrum_RW = attribute_wrapper(comms_annotation="uint32_spectrum_RW", datatype=numpy.uint32, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
+    class Uint32SpectrumDevice(LOFARDevice):
+        spectrum_R = AttributeWrapper(comms_annotation="uint32_spectrum_R", datatype=numpy.uint32, dims=SPECTRUM_DIMS)
+        spectrum_RW = AttributeWrapper(comms_annotation="uint32_spectrum_RW", datatype=numpy.uint32, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class uint64_spectrum_device(lofar_device):
-        spectrum_R = attribute_wrapper(comms_annotation="uint64_spectrum_R", datatype=numpy.uint64, dims=SPECTRUM_DIMS)
-        spectrum_RW = attribute_wrapper(comms_annotation="uint64_spectrum_RW", datatype=numpy.uint64, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
+    class Uint64SpectrumDevice(LOFARDevice):
+        spectrum_R = AttributeWrapper(comms_annotation="uint64_spectrum_R", datatype=numpy.uint64, dims=SPECTRUM_DIMS)
+        spectrum_RW = AttributeWrapper(comms_annotation="uint64_spectrum_RW", datatype=numpy.uint64, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class int16_spectrum_device(lofar_device):
-        spectrum_R = attribute_wrapper(comms_annotation="int16_spectrum_R", datatype=numpy.int16, dims=SPECTRUM_DIMS)
-        spectrum_RW = attribute_wrapper(comms_annotation="int16_spectrum_RW", datatype=numpy.int16, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
+    class Int16SpectrumDevice(LOFARDevice):
+        spectrum_R = AttributeWrapper(comms_annotation="int16_spectrum_R", datatype=numpy.int16, dims=SPECTRUM_DIMS)
+        spectrum_RW = AttributeWrapper(comms_annotation="int16_spectrum_RW", datatype=numpy.int16, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class int32_spectrum_device(lofar_device):
-        spectrum_R = attribute_wrapper(comms_annotation="int32_spectrum_R", datatype=numpy.int32, dims=SPECTRUM_DIMS)
-        spectrum_RW = attribute_wrapper(comms_annotation="int32_spectrum_RW", datatype=numpy.int32, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
+    class Int32SpectrumDevice(LOFARDevice):
+        spectrum_R = AttributeWrapper(comms_annotation="int32_spectrum_R", datatype=numpy.int32, dims=SPECTRUM_DIMS)
+        spectrum_RW = AttributeWrapper(comms_annotation="int32_spectrum_RW", datatype=numpy.int32, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class int64_spectrum_device(lofar_device):
-        spectrum_R = attribute_wrapper(comms_annotation="int64_spectrum_R", datatype=numpy.int64, dims=SPECTRUM_DIMS)
-        spectrum_RW = attribute_wrapper(comms_annotation="int64_spectrum_RW", datatype=numpy.int64, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
+    class Int64SpectrumDevice(LOFARDevice):
+        spectrum_R = AttributeWrapper(comms_annotation="int64_spectrum_R", datatype=numpy.int64, dims=SPECTRUM_DIMS)
+        spectrum_RW = AttributeWrapper(comms_annotation="int64_spectrum_RW", datatype=numpy.int64, access=AttrWriteType.READ_WRITE, dims=SPECTRUM_DIMS)
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class str_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="str_image_R", datatype=str, dims=(3,2))
-        image_RW = attribute_wrapper(comms_annotation="str_image_RW", datatype=str, access=AttrWriteType.READ_WRITE, dims=(3,2))
+    class StrImageDevice(LOFARDevice):
+        image_R = AttributeWrapper(comms_annotation="str_image_R", datatype=str, dims=(3,2))
+        image_RW = AttributeWrapper(comms_annotation="str_image_RW", datatype=str, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class bool_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="bool_image_R", datatype=bool, dims=(3,2))
-        image_RW = attribute_wrapper(comms_annotation="bool_image_RW", datatype=bool, access=AttrWriteType.READ_WRITE, dims=(3,2))
+    class BoolImageDevice(LOFARDevice):
+        image_R = AttributeWrapper(comms_annotation="bool_image_R", datatype=bool, dims=(3,2))
+        image_RW = AttributeWrapper(comms_annotation="bool_image_RW", datatype=bool, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class float32_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="float32_image_R", datatype=numpy.float32, dims=(3,2))
-        image_RW = attribute_wrapper(comms_annotation="float32_image_RW", datatype=numpy.float32, access=AttrWriteType.READ_WRITE, dims=(3,2))
+    class Float32ImageDevice(LOFARDevice):
+        image_R = AttributeWrapper(comms_annotation="float32_image_R", datatype=numpy.float32, dims=(3,2))
+        image_RW = AttributeWrapper(comms_annotation="float32_image_RW", datatype=numpy.float32, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class float64_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="float64_image_R", datatype=numpy.float64, dims=(3,2))
-        image_RW = attribute_wrapper(comms_annotation="float64_image_RW", datatype=numpy.float64, access=AttrWriteType.READ_WRITE, dims=(3,2))
+    class Float64ImageDevice(LOFARDevice):
+        image_R = AttributeWrapper(comms_annotation="float64_image_R", datatype=numpy.float64, dims=(3,2))
+        image_RW = AttributeWrapper(comms_annotation="float64_image_RW", datatype=numpy.float64, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class double_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="double_image_R", datatype=numpy.double, dims=(3,2))
-        image_RW = attribute_wrapper(comms_annotation="double_image_RW", datatype=numpy.double, access=AttrWriteType.READ_WRITE, dims=(3,2))
+    class DoubleImageDevice(LOFARDevice):
+        image_R = AttributeWrapper(comms_annotation="double_image_R", datatype=numpy.double, dims=(3,2))
+        image_RW = AttributeWrapper(comms_annotation="double_image_RW", datatype=numpy.double, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class uint8_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="uint8_image_R", datatype=numpy.uint8, dims=(3,2))
-        image_RW = attribute_wrapper(comms_annotation="uint8_image_RW", datatype=numpy.uint8, access=AttrWriteType.READ_WRITE, dims=(3,2))
+    class Uint8ImageDevice(LOFARDevice):
+        image_R = AttributeWrapper(comms_annotation="uint8_image_R", datatype=numpy.uint8, dims=(3,2))
+        image_RW = AttributeWrapper(comms_annotation="uint8_image_RW", datatype=numpy.uint8, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class uint16_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="uint16_image_R", datatype=numpy.uint16, dims=(3,2))
-        image_RW = attribute_wrapper(comms_annotation="uint16_image_RW", datatype=numpy.uint16, access=AttrWriteType.READ_WRITE, dims=(3,2))
+    class Uint16ImageDevice(LOFARDevice):
+        image_R = AttributeWrapper(comms_annotation="uint16_image_R", datatype=numpy.uint16, dims=(3,2))
+        image_RW = AttributeWrapper(comms_annotation="uint16_image_RW", datatype=numpy.uint16, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class uint32_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="uint32_image_R", datatype=numpy.uint32, dims=(3,2))
-        image_RW = attribute_wrapper(comms_annotation="uint32_image_RW", datatype=numpy.uint32, access=AttrWriteType.READ_WRITE, dims=(3,2))
+    class Uint32ImageDevice(LOFARDevice):
+        image_R = AttributeWrapper(comms_annotation="uint32_image_R", datatype=numpy.uint32, dims=(3,2))
+        image_RW = AttributeWrapper(comms_annotation="uint32_image_RW", datatype=numpy.uint32, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class uint64_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="uint64_image_R", datatype=numpy.uint64, dims=(3,2))
-        image_RW = attribute_wrapper(comms_annotation="uint64_image_RW", datatype=numpy.uint64, access=AttrWriteType.READ_WRITE, dims=(3,2))
+    class Uint64ImageDevice(LOFARDevice):
+        image_R = AttributeWrapper(comms_annotation="uint64_image_R", datatype=numpy.uint64, dims=(3,2))
+        image_RW = AttributeWrapper(comms_annotation="uint64_image_RW", datatype=numpy.uint64, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class int16_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="int16_image_R", datatype=numpy.int16, dims=(3,2))
-        image_RW = attribute_wrapper(comms_annotation="int16_image_RW", datatype=numpy.int16, access=AttrWriteType.READ_WRITE, dims=(3,2))
+    class Int16ImageDevice(LOFARDevice):
+        image_R = AttributeWrapper(comms_annotation="int16_image_R", datatype=numpy.int16, dims=(3,2))
+        image_RW = AttributeWrapper(comms_annotation="int16_image_RW", datatype=numpy.int16, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class int32_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="int32_image_R", datatype=numpy.int32, dims=(3,2))
-        image_RW = attribute_wrapper(comms_annotation="int32_image_RW", datatype=numpy.int32, access=AttrWriteType.READ_WRITE, dims=(3,2))
+    class Int32ImageDevice(LOFARDevice):
+        image_R = AttributeWrapper(comms_annotation="int32_image_R", datatype=numpy.int32, dims=(3,2))
+        image_RW = AttributeWrapper(comms_annotation="int32_image_RW", datatype=numpy.int32, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
 
-    class int64_image_device(lofar_device):
-        image_R = attribute_wrapper(comms_annotation="int64_image_R", datatype=numpy.int64, dims=(3,2))
-        image_RW = attribute_wrapper(comms_annotation="int64_image_RW", datatype=numpy.int64, access=AttrWriteType.READ_WRITE, dims=(3,2))
+    class Int64ImageDevice(LOFARDevice):
+        image_R = AttributeWrapper(comms_annotation="int64_image_R", datatype=numpy.int64, dims=(3,2))
+        image_RW = AttributeWrapper(comms_annotation="int64_image_RW", datatype=numpy.int64, access=AttrWriteType.READ_WRITE, dims=(3,2))
 
         def configure_for_initialise(self):
             dev_init(self)
@@ -497,52 +497,52 @@ class TestAttributeTypes(base.TestCase):
     """
     ATTRIBUTE_TYPE_TESTS = [
         {
-            'type': str, 'scalar': str_scalar_device,
-            'spectrum': str_spectrum_device, "image": str_image_device
+            'type': str, 'scalar': StrScalarDevice,
+            'spectrum': StrSpectrumDevice, "image": StrImageDevice
         },
         {
-            'type': bool, 'scalar': bool_scalar_device,
-            'spectrum': bool_spectrum_device, "image":  bool_image_device
+            'type': bool, 'scalar': BoolScalarDevice,
+            'spectrum': BoolSpectrumDevice, "image":  BoolImageDevice
         },
         {
-            'type': numpy.float32, 'scalar': float32_scalar_device,
-            'spectrum': float32_spectrum_device, "image": float32_image_device
+            'type': numpy.float32, 'scalar': Float32ScalarDevice,
+            'spectrum': Float32SpectrumDevice, "image": Float32ImageDevice
         },
         {
-            'type': numpy.float64, 'scalar': float64_scalar_device,
-            'spectrum': float64_spectrum_device, "image": float64_image_device
+            'type': numpy.float64, 'scalar': Float64ScalarDevice,
+            'spectrum': Float64SpectrumDevice, "image": Float64ImageDevice
         },
         {
-            'type': numpy.double, 'scalar': double_scalar_device,
-            'spectrum': double_spectrum_device, "image": double_image_device
+            'type': numpy.double, 'scalar': DoubleScalarDevice,
+            'spectrum': DoubleSpectrumDevice, "image": DoubleImageDevice
         },
         {
-            'type': numpy.uint8, 'scalar': uint8_scalar_device,
-            'spectrum': uint8_spectrum_device, "image": uint8_image_device
+            'type': numpy.uint8, 'scalar': Uint8ScalarDevice,
+            'spectrum': Uint8SpectrumDevice, "image": Uint8ImageDevice
         },
         {
-            'type': numpy.uint16, 'scalar': uint16_scalar_device,
-            'spectrum': uint16_spectrum_device, "image": uint16_image_device
+            'type': numpy.uint16, 'scalar': Uint16ScalarDevice,
+            'spectrum': Uint16SpectrumDevice, "image": Uint16ImageDevice
         },
         {
-            'type': numpy.uint32, 'scalar': uint32_scalar_device,
-            'spectrum': uint32_spectrum_device, "image": uint32_image_device
+            'type': numpy.uint32, 'scalar': Uint32ScalarDevice,
+            'spectrum': Uint32SpectrumDevice, "image": Uint32ImageDevice
         },
         {
-            'type': numpy.uint64, 'scalar': uint64_scalar_device,
-            'spectrum': uint64_spectrum_device, "image": uint64_image_device
+            'type': numpy.uint64, 'scalar': Uint64ScalarDevice,
+            'spectrum': Uint64SpectrumDevice, "image": Uint64ImageDevice
         },
         {
-            'type': numpy.int16, 'scalar': int16_scalar_device,
-            'spectrum': int16_spectrum_device, "image": int16_image_device
+            'type': numpy.int16, 'scalar': Int16ScalarDevice,
+            'spectrum': Int16SpectrumDevice, "image": Int16ImageDevice
         },
         {
-            'type': numpy.int32, 'scalar': int32_scalar_device,
-            'spectrum': int32_spectrum_device, "image": int32_image_device
+            'type': numpy.int32, 'scalar': Int32ScalarDevice,
+            'spectrum': Int32SpectrumDevice, "image": Int32ImageDevice
         },
         {
-            'type': numpy.int64, 'scalar': int64_scalar_device,
-            'spectrum': int64_spectrum_device, "image": int64_image_device
+            'type': numpy.int64, 'scalar': Int64ScalarDevice,
+            'spectrum': Int64SpectrumDevice, "image": Int64ImageDevice
         }
     ]
 
@@ -623,12 +623,12 @@ class TestAttributeAccess(base.TestCase):
         self.deviceproxy_patch.start()
         self.addCleanup(self.deviceproxy_patch.stop)
 
-    class float32_scalar_device(lofar_device):
-        scalar_R = attribute_wrapper(comms_annotation="float32_scalar_R", datatype=numpy.float32)
-        scalar_RW = attribute_wrapper(comms_annotation="float32_scalar_RW", datatype=numpy.float32, access=AttrWriteType.READ_WRITE)
+    class float32_scalar_device(LOFARDevice):
+        scalar_R = AttributeWrapper(comms_annotation="float32_scalar_R", datatype=numpy.float32)
+        scalar_RW = AttributeWrapper(comms_annotation="float32_scalar_RW", datatype=numpy.float32, access=AttrWriteType.READ_WRITE)
 
-        spectrum_RW = attribute_wrapper(comms_annotation="spectrum_RW", dims=(3,), datatype=numpy.float32, access=AttrWriteType.READ_WRITE)
-        image_RW = attribute_wrapper(comms_annotation="image_RW", dims=(3,2), datatype=numpy.float32, access=AttrWriteType.READ_WRITE)
+        spectrum_RW = AttributeWrapper(comms_annotation="spectrum_RW", dims=(3,), datatype=numpy.float32, access=AttrWriteType.READ_WRITE)
+        image_RW = AttributeWrapper(comms_annotation="image_RW", dims=(3,2), datatype=numpy.float32, access=AttrWriteType.READ_WRITE)
 
         def configure_for_initialise(self):
             dev_init(self)
diff --git a/tangostationcontrol/tangostationcontrol/test/clients/test_client.py b/tangostationcontrol/tangostationcontrol/test/clients/test_client.py
index 8bf63cd8dfe4f77938d5cdca5c037cb0b69d3791..98d3dd8f0b28e1db64f915f99caf781ec242a8fe 100644
--- a/tangostationcontrol/tangostationcontrol/test/clients/test_client.py
+++ b/tangostationcontrol/tangostationcontrol/test/clients/test_client.py
@@ -8,7 +8,7 @@ from tangostationcontrol.clients.comms_client import CommClient
 import logging
 logger = logging.getLogger()
 
-class test_client(CommClient):
+class TestClient(CommClient):
     """
     this class provides an example implementation of a comms_client.
     During initialisation it creates a correctly shaped zero filled value. on read that value is returned and on write its modified.
@@ -59,7 +59,7 @@ class test_client(CommClient):
 
     def _setup_value_conversion(self, attribute):
         """
-        gives the client access to the attribute_wrapper object in order to access all
+        gives the client access to the AttributeWrapper object in order to access all
         necessary data such as dimensionality and data type
         """
 
@@ -99,7 +99,7 @@ class test_client(CommClient):
 
             self.values[annotation] = write_value
 
-        logger.debug("created and bound example_client read/write functions to attribute_wrapper object")
+        logger.debug("created and bound example_client read/write functions to AttributeWrapper object")
         return read_function, write_function
 
     async def setup_attribute(self, annotation=None, attribute=None):
@@ -111,7 +111,7 @@ class test_client(CommClient):
         # process the comms_annotation
         self._setup_annotation(annotation)
 
-        # get all the necessary data to set up the read/write functions from the attribute_wrapper
+        # get all the necessary data to set up the read/write functions from the AttributeWrapper
         dims, dtype = self._setup_value_conversion(attribute)
 
         # configure and return the read/write functions
diff --git a/tangostationcontrol/tangostationcontrol/test/clients/test_opcua_client.py b/tangostationcontrol/tangostationcontrol/test/clients/test_opcua_client.py
index a33226898d681520849609e85606b015583da488..a0579e8b9552cecdeb89b42e280c63c2154848a9 100644
--- a/tangostationcontrol/tangostationcontrol/test/clients/test_opcua_client.py
+++ b/tangostationcontrol/tangostationcontrol/test/clients/test_opcua_client.py
@@ -13,24 +13,24 @@ from tangostationcontrol.clients import opcua_client
 from tangostationcontrol.test import base
 
 
-class attr_props:
+class AttrProps:
     def __init__(self, numpy_type):
         self.numpy_type = numpy_type
 
 
 ATTR_TEST_TYPES = [
-    attr_props(numpy_type=bool),
-    attr_props(numpy_type=str),
-    attr_props(numpy_type=numpy.float32),
-    attr_props(numpy_type=numpy.float64),
-    attr_props(numpy_type=numpy.double),
-    attr_props(numpy_type=numpy.uint8),
-    attr_props(numpy_type=numpy.uint16),
-    attr_props(numpy_type=numpy.uint32),
-    attr_props(numpy_type=numpy.uint64),
-    attr_props(numpy_type=numpy.int16),
-    attr_props(numpy_type=numpy.int32),
-    attr_props(numpy_type=numpy.int64)
+    AttrProps(numpy_type=bool),
+    AttrProps(numpy_type=str),
+    AttrProps(numpy_type=numpy.float32),
+    AttrProps(numpy_type=numpy.float64),
+    AttrProps(numpy_type=numpy.double),
+    AttrProps(numpy_type=numpy.uint8),
+    AttrProps(numpy_type=numpy.uint16),
+    AttrProps(numpy_type=numpy.uint32),
+    AttrProps(numpy_type=numpy.uint64),
+    AttrProps(numpy_type=numpy.int16),
+    AttrProps(numpy_type=numpy.int32),
+    AttrProps(numpy_type=numpy.int64)
 ]
 
 SCALAR_SHAPE = (1,)
@@ -92,7 +92,7 @@ class TestOPCua(base.AsyncTestCase):
         m_opc_client.return_value = m_opc_client_members
 
         for i in ATTR_TEST_TYPES:
-            class mock_attr:
+            class MockAttr:
                 def __init__(self, dtype, x, y):
                     self.datatype = dtype
                     self.dim_x = x
@@ -107,7 +107,7 @@ class TestOPCua(base.AsyncTestCase):
                     dim_y = j[0]
 
                 # create a fake attribute with only the required variables in it.
-                m_attribute = mock_attr(i.numpy_type, dim_x, dim_y)
+                m_attribute = MockAttr(i.numpy_type, dim_x, dim_y)
 
                 # pretend like there is a running OPCua server with a node that has this name
                 m_annotation = [f"2:testNode_{str(i.numpy_type)}_{str(dim_x)}_{str(dim_y)}"]
@@ -124,7 +124,7 @@ class TestOPCua(base.AsyncTestCase):
     def test_protocol_attr(self):
         """
         This tests finding an OPCua node and returning a valid object with read/write functions.
-        (This step is normally initiated by the attribute_wrapper)
+        (This step is normally initiated by the AttributeWrapper)
         """
 
         # for all datatypes
diff --git a/tangostationcontrol/tangostationcontrol/test/clients/test_snmp_client.py b/tangostationcontrol/tangostationcontrol/test/clients/test_snmp_client.py
index 8cc912c5f43a457f807769a3fa6d3c867b104e32..c08926ed109ec35bbf6c6ff896ce47e1ed97e093 100644
--- a/tangostationcontrol/tangostationcontrol/test/clients/test_snmp_client.py
+++ b/tangostationcontrol/tangostationcontrol/test/clients/test_snmp_client.py
@@ -7,10 +7,13 @@ import numpy
 from unittest import mock
 from tangostationcontrol.test import base
 
-from tangostationcontrol.clients.snmp_client import SNMP_client, snmp_attribute, SNMP_comm, mib_loader
+from tangostationcontrol.clients.snmp_client import SNMPAttribute
+from tangostationcontrol.clients.snmp_client import SNMPComm
+from tangostationcontrol.clients.snmp_client import SNMPClient
+from tangostationcontrol.clients.snmp_client import MIBLoader
 
 
-class server_imitator:
+class SNMPServerFixture:
     # conversion dict
     SNMP_TO_NUMPY_DICT = {
         hlapi.Integer32: numpy.int64,
@@ -97,6 +100,7 @@ class server_imitator:
 
         return check_val
 
+
 class TestSNMP(base.TestCase):
 
     def test_annotation_fail(self):
@@ -104,7 +108,7 @@ class TestSNMP(base.TestCase):
         unit test for the processing of annotation. Has 2 lists. 1 with things that should succeed and 1 with things that should fail.
         """
 
-        client = SNMP_client(community='public', host='localhost', version=1, timeout=10, fault_func=None, try_interval=2)
+        client = SNMPClient(community='public', host='localhost', version=1, timeout=10, fault_func=None, try_interval=2)
 
         fail_list = [
             # no 'name'
@@ -119,13 +123,13 @@ class TestSNMP(base.TestCase):
 
     @mock.patch('pysnmp.hlapi.ObjectIdentity')
     @mock.patch('pysnmp.hlapi.ObjectType')
-    @mock.patch('tangostationcontrol.clients.snmp_client.SNMP_comm.getter')
+    @mock.patch('tangostationcontrol.clients.snmp_client.SNMPComm.getter')
     def test_snmp_obj_get(self, m_next, m_obj_T, m_obj_i):
         """
         Attempts to read a fake SNMP variable and checks whether it got what it expected
         """
 
-        server = server_imitator()
+        server = SNMPServerFixture()
 
         for j in server.DIM_LIST:
             for i in server.SNMP_TO_NUMPY_DICT:
@@ -134,10 +138,10 @@ class TestSNMP(base.TestCase):
                 def __fakeInit__(self):
                     pass
 
-                with mock.patch.object(SNMP_comm, '__init__', __fakeInit__):
-                    m_comms = SNMP_comm()
+                with mock.patch.object(SNMPComm, '__init__', __fakeInit__):
+                    m_comms = SNMPComm()
 
-                    snmp_attr = snmp_attribute(comm=m_comms, mib="test", name="test", idx=0, dtype=server.SNMP_TO_NUMPY_DICT[i], dim_x=server.DIM_LIST[j][0], dim_y=server.DIM_LIST[j][1])
+                    snmp_attr = SNMPAttribute(comm=m_comms, mib="test", name="test", idx=0, dtype=server.SNMP_TO_NUMPY_DICT[i], dim_x=server.DIM_LIST[j][0], dim_y=server.DIM_LIST[j][1])
 
                     val = snmp_attr.read_function()
 
@@ -147,30 +151,31 @@ class TestSNMP(base.TestCase):
     @mock.patch('pysnmp.hlapi.ObjectIdentity')
     @mock.patch('pysnmp.hlapi.ObjectType')
     @mock.patch('pysnmp.hlapi.setCmd')
-    @mock.patch('tangostationcontrol.clients.snmp_client.SNMP_comm.setter')
+    @mock.patch('tangostationcontrol.clients.snmp_client.SNMPComm.setter')
     def test_snmp_obj_set(self, m_next, m_nextCmd, m_obj_T, m_obj_ID):
         """
         Attempts to write a value to an SNMP server, but instead intercepts it and compared whether the values is as expected.
         """
-        server = server_imitator()
+
+        server = SNMPServerFixture()
         obj_type = hlapi.ObjectType
 
         for j in server.DIM_LIST:
             for i in server.SNMP_TO_NUMPY_DICT:
-                # mocks the return value of the next function in snmp_client.SNMP_comm.setter
+                # mocks the return value of the next function in snmp_client.SNMPComm.setter
                 m_next.return_value = (None, None, None, server.get_return_val(i, server.DIM_LIST[j]))
 
                 def __fakeInit__(self):
                     pass
 
-                with mock.patch.object(SNMP_comm, '__init__', __fakeInit__):
-                    m_comms = SNMP_comm()
+                with mock.patch.object(SNMPComm, '__init__', __fakeInit__):
+                    m_comms = SNMPComm()
 
                     set_val = server.val_check(i, server.DIM_LIST[j])
 
                     # create an SNMP attribute object and temporarily
                     hlapi.ObjectType = obj_type
-                    snmp_attr = snmp_attribute(comm=m_comms, mib="test", name="test", idx=0, dtype=server.SNMP_TO_NUMPY_DICT[i], dim_x=server.DIM_LIST[j][0], dim_y=server.DIM_LIST[j][1])
+                    snmp_attr = SNMPAttribute(comm=m_comms, mib="test", name="test", idx=0, dtype=server.SNMP_TO_NUMPY_DICT[i], dim_x=server.DIM_LIST[j][0], dim_y=server.DIM_LIST[j][1])
 
                     hlapi.ObjectType = mock.MagicMock()
 
@@ -190,13 +195,11 @@ class TestSNMP(base.TestCase):
 
         hlapi.ObjectType = obj_type
 
-
-    @mock.patch('tangostationcontrol.clients.snmp_client.SNMP_comm.getter')
+    @mock.patch('tangostationcontrol.clients.snmp_client.SNMPComm.getter')
     def test_named_value(self, m_next):
 
         m_comms = mock.Mock()
-        snmp_attr = snmp_attribute(comm=m_comms, mib="test", name="test", idx=0, dtype=str, dim_x=1, dim_y=0)
-
+        snmp_attr = SNMPAttribute(comm=m_comms, mib="test", name="test", idx=0, dtype=str, dim_x=1, dim_y=0)
 
         # create a named integer with the values: 'enable' for 1 and 'disable' for 0
         test_val = [[(None, hlapi.Integer.withNamedValues(enable=1, disable=0)(1),)]]
@@ -205,7 +208,6 @@ class TestSNMP(base.TestCase):
         # should return 'enable' since we supplied the value 1
         self.assertEqual(ret_val, "enable", f"Expected: to get 'enable', got: {ret_val} of type {type(ret_val)}")
 
-
         # create an unnamed integer with a value of 2
         test_val = [[(None, hlapi.Integer(2),)]]
         ret_val = snmp_attr.convert(test_val)
@@ -214,10 +216,8 @@ class TestSNMP(base.TestCase):
         self.assertEqual(ret_val, 2, f"Expected: to get {2}, got: {ret_val} of type {type(ret_val)}")
 
 
-
 class TestMibLoading(base.TestCase):
-
-    #name and directory of the pymib file
+    # name and directory of the pymib file
     MIB = "TEST-MIB"
 
     # mib file is in a folder that is in the same folder as this test
@@ -232,7 +232,7 @@ class TestMibLoading(base.TestCase):
         """
 
         abs_dir = path.dirname(__file__) + "/" + self.REL_DIR + "/"
-        loader = mib_loader(abs_dir)
+        loader = MIBLoader(abs_dir)
 
         loader.load_pymib(self.MIB)
 
@@ -263,8 +263,7 @@ class TestMibLoading(base.TestCase):
 
     def test_mib_missing(self):
         abs_dir = path.dirname(__file__) + "/" + self.REL_DIR + "/"
-        loader = mib_loader(abs_dir)
+        loader = MIBLoader(abs_dir)
 
         with self.assertRaises(error.MibNotFoundError):
             loader.load_pymib("FAKE-MIB")
-
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/automatic_polling_performance_test/Tango_Controls-Automatic_polling_performance_test.md b/tangostationcontrol/tangostationcontrol/test/devices/automatic_polling_performance_test/Tango_Controls-Automatic_polling_performance_test.md
index 3078d28472daf767475b070ad85492e785167b1e..5f7e4e9afc94b3dc502624650b14b3884f9474a0 100644
--- a/tangostationcontrol/tangostationcontrol/test/devices/automatic_polling_performance_test/Tango_Controls-Automatic_polling_performance_test.md
+++ b/tangostationcontrol/tangostationcontrol/test/devices/automatic_polling_performance_test/Tango_Controls-Automatic_polling_performance_test.md
@@ -20,7 +20,7 @@ Please refer to the reference documents for in-depth information about the autom
 - Two devices run in the same DS.
     - Tango DB is modified to have a DS named  `monitoring_performance_test/1`.
     
-    - Tango DB is modified to have the DS named `monitoring_performance_test/1` run two devices named `test/monitoring_performance/1` and `test/monitoring_performance/2`. Both devices instantiate the same class `Monitoring_Performance_Device`.
+    - Tango DB is modified to have the DS named `monitoring_performance_test/1` run two devices named `test/monitoring_performance/1` and `test/monitoring_performance/2`. Both devices instantiate the same class `MonitoringPerformanceDevice`.
     
     - Execute the DS like this: `bin/start-DS.sh devices/test/devices/automatic_polling_performance_test/monitoring_performance_test.py 1`
     
@@ -233,4 +233,4 @@ d2
 	max = 1.003[s]
 	median = 0.999[s]
 	mean = 0.9997[s]
-	stddev = 0.002491987158875375[s]
\ No newline at end of file
+	stddev = 0.002491987158875375[s]
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/automatic_polling_performance_test/automatic_polling_performance_test.json b/tangostationcontrol/tangostationcontrol/test/devices/automatic_polling_performance_test/automatic_polling_performance_test.json
index 0fa271289f3254df9c61158dd1a94b9884945b09..80459b2ab101b7d140661a193d48e9a1f65295e6 100644
--- a/tangostationcontrol/tangostationcontrol/test/devices/automatic_polling_performance_test/automatic_polling_performance_test.json
+++ b/tangostationcontrol/tangostationcontrol/test/devices/automatic_polling_performance_test/automatic_polling_performance_test.json
@@ -5,7 +5,7 @@
         {
             "1":
             {
-                "Monitoring_Performance_Device":
+                "MonitoringPerformanceDevice":
                 {
                     "test/monitoring_performance/1":
                     {
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/automatic_polling_performance_test/monitoring_performance_test.py b/tangostationcontrol/tangostationcontrol/test/devices/automatic_polling_performance_test/monitoring_performance_test.py
index 131d1f2bec8368ffebbc7cf45665edde00a67754..820dc64cc42c8f47448be8a84153a16d95fbd731 100644
--- a/tangostationcontrol/tangostationcontrol/test/devices/automatic_polling_performance_test/monitoring_performance_test.py
+++ b/tangostationcontrol/tangostationcontrol/test/devices/automatic_polling_performance_test/monitoring_performance_test.py
@@ -19,13 +19,13 @@ import numpy
 from tango import DevState, Util
 from tango.server import run, Device, attribute
 
-__all__ = ["Monitoring_Performance_Device", "main"]
+__all__ = ["MonitoringPerformanceDevice", "main"]
 
 POLLING_THREADS = 100
 ARRAY_SIZE = 2000000
 
 
-class Monitoring_Performance_Device(Device):
+class MonitoringPerformanceDevice(Device):
     global ARRAY_SIZE
     def read_array(self):
         print("{} {}".format(time.time(), self.get_name()))
@@ -114,7 +114,7 @@ class Monitoring_Performance_Device(Device):
         self.set_state(DevState.OFF)
 
 def main(args = None, **kwargs):
-    return run((Monitoring_Performance_Device, ), args = args, **kwargs)
+    return run((MonitoringPerformanceDevice, ), args = args, **kwargs)
 
 if __name__ == '__main__':
     main()
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/random_data.py b/tangostationcontrol/tangostationcontrol/test/devices/random_data.py
index bafa9ca40b74753dd5c149ee8eaab601d9549d0b..73499090165a2a8a3564a619eaa9ca1f328090ed 100644
--- a/tangostationcontrol/tangostationcontrol/test/devices/random_data.py
+++ b/tangostationcontrol/tangostationcontrol/test/devices/random_data.py
@@ -12,9 +12,9 @@ from tango import DevState
 from tango.server import run, Device, attribute
 from numpy import random, double
 
-__all__ = ["Random_Data", "main"]
+__all__ = ["RandomData", "main"]
 
-class Random_Data(Device):
+class RandomData(Device):
     """
     Random data monitor point device
     """
@@ -489,4 +489,4 @@ def main(args = None, **kwargs):
     """
     Main function of the RandomData module.
     """
-    return run((Random_Data,), args = args, **kwargs)
+    return run((RandomData,), args = args, **kwargs)
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/test_lofar_device.py b/tangostationcontrol/tangostationcontrol/test/devices/test_lofar_device.py
index 3a91941bb1366c98ef07b04709d72655effc7f00..7a0cf7b18455456eb0f46cf4e8742ca06e17af11 100644
--- a/tangostationcontrol/tangostationcontrol/test/devices/test_lofar_device.py
+++ b/tangostationcontrol/tangostationcontrol/test/devices/test_lofar_device.py
@@ -33,7 +33,7 @@ class TestLofarDevice(device_base.DeviceTestCase):
     def test_read_attribute(self):
         """ Test whether read_attribute really returns the attribute. """
 
-        class MyLofarDevice(lofar_device.lofar_device):
+        class MyLofarDevice(lofar_device.LOFARDevice):
             @attribute(dtype=float)
             def A(self):
                 return 42.0
@@ -56,7 +56,7 @@ class TestLofarDevice(device_base.DeviceTestCase):
             self.assertListEqual([42.0, 43.0], proxy.read_attribute_B_array.tolist())
 
     def test_disable_state(self):
-        with DeviceTestContext(lofar_device.lofar_device, process=True, timeout=10) as proxy:
+        with DeviceTestContext(lofar_device.LOFARDevice, process=True, timeout=10) as proxy:
             proxy.initialise()
             self.assertEqual(DevState.STANDBY, proxy.state())
             proxy.on()
@@ -65,7 +65,7 @@ class TestLofarDevice(device_base.DeviceTestCase):
             self.assertEqual(DevState.DISABLE, proxy.state())
 
     def test_disable_state_transitions(self):
-        with DeviceTestContext(lofar_device.lofar_device, process=True, timeout=10) as proxy:
+        with DeviceTestContext(lofar_device.LOFARDevice, process=True, timeout=10) as proxy:
             proxy.off()
             with self.assertRaises(DevFailed):
                 proxy.disable_hardware()
@@ -77,7 +77,7 @@ class TestLofarDevice(device_base.DeviceTestCase):
     def test_atomic_read_modify_write(self):
         """Test atomic read modify write for attribute"""
 
-        class AttributeLofarDevice(lofar_device.lofar_device):
+        class AttributeLofarDevice(lofar_device.LOFARDevice):
 
             BOOL_ARRAY_DIM = 32
 
diff --git a/tangostationcontrol/tox.ini b/tangostationcontrol/tox.ini
index fe85f17def0e960abe37c634e309337549623496..d562136911bdfaf7a8970b3d0d578f3739475555 100644
--- a/tangostationcontrol/tox.ini
+++ b/tangostationcontrol/tox.ini
@@ -75,7 +75,6 @@ commands =
     {envpython} -m coverage xml -o coverage.xml
     {envpython} -m coverage report --omit='*test*'
 
-; TODO(Corne): Integrate Hacking to customize pep8 rules
 [testenv:pep8]
 commands =
     {envpython} -m doc8 --version