diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 18b0dd91fe27ab8b63ec625e8121553689513255..64e26f5b2b5659db05a6cd975e3d2ac30be5ef64 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,4 +1,4 @@
-image: git.astron.nl:5000/lofar2.0/tango/tango-itango:9.3.7
+image: git.astron.nl:5000/lofar2.0/tango/lofar-device-base:latest
 variables:
   GIT_SUBMODULE_STRATEGY: recursive
   PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
@@ -42,6 +42,11 @@ stages:
     - . bootstrap/etc/lofar20rc.sh || true
 ##    Allow docker image script to execute
 #    - chmod u+x $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh
+# This suffers from only refs changes not working as expected:
+# https://gitlab.com/gitlab-org/gitlab-foss/-/issues/55012
+# Therefore we have to add `only: refs: - merge_requests` to all jobs that are
+# only supposed to run on merge requests with file changes. However,
+# two pipelines will spawn instead of one of which one tagged with 'detached`.
 .base_docker_images_except:
   extends: .base_docker_images
   except:
@@ -62,6 +67,8 @@ docker_store_images_master_tag:
 docker_store_images_changes:
   extends: .base_docker_store_images
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/.env
   except:
@@ -101,6 +108,8 @@ docker_build_image_all:
 docker_build_image_elk:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/elk.yml
       - docker-compose/elk/*
@@ -112,6 +121,8 @@ docker_build_image_elk:
 docker_build_image_lofar_device_base:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/lofar-device-base.yml
       - docker-compose/lofar-device-base/*
@@ -121,27 +132,30 @@ docker_build_image_lofar_device_base:
 docker_build_image_prometheus:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/prometheus.yml
       - docker-compose/prometheus/*
-  except:
-    refs:
-      - tags
-      - master
   script:
 #    Do not remove 'bash' or statement will be ignored by primitive docker shell
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh prometheus $tag
 docker_build_image_itango:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/itango.yml
+      - docker-compose/itango/*
   script:
 #    Do not remove 'bash' or statement will be ignored by primitive docker shell
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh itango $tag
 docker_build_image_grafana:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/grafana.yml
       - docker-compose/grafana/*
@@ -151,6 +165,8 @@ docker_build_image_grafana:
 docker_build_image_jupyter:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/jupyter.yml
       - docker-compose/jupyter/*
@@ -160,6 +176,8 @@ docker_build_image_jupyter:
 docker_build_image_apsct_sim:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/aspct-sim.yml
       - docker-compose/pypcc-sim-base/*
@@ -169,6 +187,8 @@ docker_build_image_apsct_sim:
 docker_build_image_apspu_sim:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/apspu-sim.yml
       - docker-compose/pypcc-sim-base/*
@@ -178,6 +198,8 @@ docker_build_image_apspu_sim:
 docker_build_image_recv_sim:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/recv-sim.yml
       - docker-compose/pypcc-sim-base/*
@@ -187,6 +209,8 @@ docker_build_image_recv_sim:
 docker_build_image_sdptr_sim:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/sdptr-sim.yml
       - docker-compose/sdptr-sim/*
@@ -196,6 +220,8 @@ docker_build_image_sdptr_sim:
 docker_build_image_unb2_sim:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/unb2-sim.yml
       - docker-compose/pypcc-sim-base/*
@@ -205,6 +231,8 @@ docker_build_image_unb2_sim:
 docker_build_image_device_apsct:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/device-aspct.yml
       - docker-compose/lofar-device-base/*
@@ -214,6 +242,8 @@ docker_build_image_device_apsct:
 docker_build_image_device_apspu:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/device-apspu.yml
       - docker-compose/lofar-device-base/*
@@ -223,6 +253,8 @@ docker_build_image_device_apspu:
 docker_build_image_device_boot:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/device-boot.yml
       - docker-compose/lofar-device-base/*
@@ -232,6 +264,8 @@ docker_build_image_device_boot:
 docker_build_image_device_docker:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/device-docker.yml
       - docker-compose/lofar-device-base/*
@@ -241,6 +275,8 @@ docker_build_image_device_docker:
 docker_build_image_device_ovservation_control:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/device-observation_control.yml
       - docker-compose/lofar-device-base/*
@@ -250,6 +286,8 @@ docker_build_image_device_ovservation_control:
 docker_build_image_device_recv:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/device-recv.yml
       - docker-compose/lofar-device-base/*
@@ -259,6 +297,8 @@ docker_build_image_device_recv:
 docker_build_image_device_sdp:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/device-sdp.yml
       - docker-compose/lofar-device-base/*
@@ -268,6 +308,8 @@ docker_build_image_device_sdp:
 docker_build_image_device_sst:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/device-sst.yml
       - docker-compose/lofar-device-base/*
@@ -277,6 +319,8 @@ docker_build_image_device_sst:
 docker_build_image_device_unb2:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/device-unb2.yml
       - docker-compose/lofar-device-base/*
@@ -286,6 +330,8 @@ docker_build_image_device_unb2:
 docker_build_image_device_xst:
   extends: .base_docker_images_except
   only:
+    refs:
+      - merge_requests
     changes:
       - docker-compose/device-xst.yml
       - docker-compose/lofar-device-base/*
diff --git a/docker-compose/itango/Dockerfile b/docker-compose/itango/Dockerfile
index 044ae985c4d1d45c26a6c00f6c3a455b93187cff..448afacfe687f6b75b163c159a779ff14ec07ee3 100644
--- a/docker-compose/itango/Dockerfile
+++ b/docker-compose/itango/Dockerfile
@@ -4,7 +4,8 @@ FROM ${SOURCE_IMAGE}
 RUN sudo apt-get -y update && \
     sudo apt-get -y upgrade && \
     sudo apt-get -y install apt-file apt-transport-https apt-utils aptitude && \
-    sudo aptitude -y install htop iftop iproute2 mc most net-tools tcpdump telnet tmux traceroute vim xterm git && \
+    sudo apt-get -y install htop iftop iproute2 mc most net-tools tcpdump && \
+    sudo apt-get -y install telnet tmux traceroute vim xterm git && \
     sudo aptitude clean && \
     sudo aptitude autoclean
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/abstract_device.py b/tangostationcontrol/tangostationcontrol/devices/abstract_device.py
deleted file mode 100644
index c3c6aea23d0af39f80dd733efb4c911847d93635..0000000000000000000000000000000000000000
--- a/tangostationcontrol/tangostationcontrol/devices/abstract_device.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of the XXX project
-#
-#
-#
-# Distributed under the terms of the APACHE license.
-# See LICENSE.txt for more info.
-
-"""Abstract Device Meta for LOFAR2.0
-
-"""
-
-import logging
-
-from tango.server import DeviceMeta
-
-logger = logging.getLogger()
-
-
-# TODO(Corne): Fix combining metaclasses by iterating over their variables and
-#              methods. https://support.astron.nl/jira/browse/L2SS-551
-# class AbstractDeviceMetas(DeviceMeta, ABCMeta):
-class AbstractDeviceMetas(DeviceMeta):
-    """Collects meta classes to allow lofar_device to be both a Device and an ABC. """
-
-    def __new__(mcs, name, bases, namespace, **kwargs):
-        cls = DeviceMeta.__new__(mcs, name, bases, namespace, **kwargs)
-        # temp_cls = ABCMeta.__new__(mcs, name, bases, namespace)
-        # setattr(cls, '__abstractmethods__', temp_cls.__abstractmethods__)
-        # setattr(cls, '_abc_impl', temp_cls._abc_impl)
-        return cls
diff --git a/tangostationcontrol/tangostationcontrol/devices/beam.py b/tangostationcontrol/tangostationcontrol/devices/beam.py
index a44a557a3fbb875d7f623ce05ed039576cdc69f7..3330d3a3b2be83035d9915ccb5b421e7912a995b 100644
--- a/tangostationcontrol/tangostationcontrol/devices/beam.py
+++ b/tangostationcontrol/tangostationcontrol/devices/beam.py
@@ -8,18 +8,17 @@
 """
 
 import numpy
+import datetime
+from tango.server import attribute, command, device_property
+from tango import AttrWriteType, DebugIt, DevState, DeviceProxy, DevVarStringArray, DevVarDoubleArray
 
-from tango.server import attribute
-from tango.server import command
-from tango import AttrWriteType
-from tango import DevState
-from tango import DebugIt
-
+# Additional import
 from tangostationcontrol.common.entrypoint import entry
-from tangostationcontrol.devices.device_decorators import only_in_states
 from tangostationcontrol.devices.lofar_device import lofar_device
 from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
 from tangostationcontrol.common.measures import get_measures_directory, use_measures_directory, download_measures, restart_python, get_available_measures_directories
+from tangostationcontrol.beam.delays import delay_calculator
+from tangostationcontrol.devices.device_decorators import *
 
 import logging
 logger = logging.getLogger()
@@ -30,32 +29,35 @@ __all__ = ["Beam", "main"]
 @device_logging_to_python()
 class Beam(lofar_device):
 
-    _hbat_pointing_direction = numpy.zeros(96)
-    _hbat_pointing_epoch = numpy.zeros(96)
-
-    @property
-    def hbat_pointing_direction(self):
-        return tuple(self._hbat_pointing_direction)
-
-    @property
-    def hbat_pointing_epoch(self):
-        return tuple(self._hbat_pointing_epoch)
+    _hbat_pointing_direction = numpy.zeros((96,3), dtype=numpy.str)
+    _hbat_pointing_timestamp = numpy.zeros(96, dtype=numpy.double)
 
     # -----------------
     # Device Properties
     # -----------------
+    reference_itrf =  device_property(
+        dtype='DevVarFloatArray',
+        mandatory=False,
+        default_value = numpy.tile(numpy.array([3826577.066, 461022.948, 5064892.786]),(96,1)) # CS002LBA, in ITRF2005 timestamp 2012.5
+    )
+
+    antenna_itrf = device_property(
+        dtype='DevVarFloatArray',
+        mandatory=False,
+        default_value = numpy.tile(numpy.array([3826923.546, 460915.441, 5064643.489]),(96,16,1)) # CS001LBA, in ITRF2005 timestamp 2012.5
+    )
 
     # ----------
     # Attributes
     # ----------
 
     HBAT_pointing_direction_R = attribute(access=AttrWriteType.READ,
-        dtype=(numpy.double,), max_dim_x=96,
-        fget=lambda self: self.hbat_pointing_direction)
+        dtype=((numpy.str,),), max_dim_x=3, max_dim_y=96,
+        fget=lambda self: self._hbat_pointing_direction)
 
-    HBAT_pointing_epoch_R = attribute(access=AttrWriteType.READ,
+    HBAT_pointing_timestamp_R = attribute(access=AttrWriteType.READ,
         dtype=(numpy.double,), max_dim_x=96,
-        fget=lambda self: self.hbat_pointing_epoch)
+        fget=lambda self: self._hbat_pointing_timestamp)
 
     # Directory where the casacore measures that we use, reside. We configure ~/.casarc to
     # use the symlink /opt/IERS/current, which we switch to the actual set of files to use.
@@ -67,32 +69,72 @@ class Beam(lofar_device):
     # --------
     # overloaded functions
     # --------
+    @log_exceptions()
+    def configure_for_initialise(self):
+        super().configure_for_initialise()
+
+        # Set a reference of RECV device
+        self.recv_proxy = DeviceProxy("STAT/RECV/1")
 
     # --------
-    # Commands
+    # internal functions
     # --------
 
-    @DebugIt()
-    @command(dtype_in=(numpy.double,), dtype_out=int)
-    @only_in_states([DevState.STANDBY, DevState.ON])
-    def set_direction_pointings(self, new_points: numpy.array):
-        if new_points.size != 96:
-            return -1
-
-        self._hbat_pointing_direction = new_points
-
-        return 0
+    def _HBAT_delays(self, pointing_direction: numpy.array, timestamp: datetime.datetime = datetime.datetime.now()):
+        """
+        Calculate the delays (in seconds) based on the pointing list and the timestamp
+        TBD: antenna and reference positions will be retrieved from RECV and not stored as BEAM device properties
+        """
+
+        delays = numpy.zeros((96,16), dtype=numpy.float64)
+
+        for tile in range(96):
+            # initialise delay calculator
+            d = delay_calculator(self.reference_itrf[tile])
+            d.set_measure_time(timestamp)
+
+            # calculate the delays based on the set reference position, the set time and now the set direction and antenna positions
+            delays[tile] = d.convert(pointing_direction[tile], self.antenna_itrf[tile])    
+
+        return delays
+
+    @staticmethod
+    def _calculate_HBAT_bf_delays(delays: numpy.ndarray):
+        """
+        Helper function that converts a signal path delay (in seconds) to an analog beam weight,
+        which is a value per tile per dipole per polarisation.
+        """
+        # Duplicate delay values per polarisation
+        polarised_delays = numpy.tile(delays, 2)                      # output dims -> 96x32             
+
+        # Divide by 0.5ns and round
+        HBAT_bf_delays = numpy.array(polarised_delays / 0.5e-09, dtype=numpy.int64)
+
+        return HBAT_bf_delays
+
+    def _HBAT_set_pointing(self, pointing_direction: numpy.array, timestamp: datetime.datetime = datetime.datetime.now()):
+        """
+        Uploads beam weights based on a given pointing direction 2D array (96 tiles x 3 parameters)
+        """
+        # Retrieve delays from casacore
+        delays = self._HBAT_delays(pointing_direction, timestamp)
+        # Convert delays into beam weights
+        HBAT_bf_delays = self._calculate_HBAT_bf_delays(delays)
+
+        # Write weights to RECV
+        self.recv_proxy.HBAT_BF_delays_RW = HBAT_bf_delays
+
+        # Record where we now point to, now that we've updated the weights.
+        # Only the entries within the mask have been updated
+        mask = self.recv_proxy.Ant_mask_RW.flatten()
+        for rcu in range(96):
+            if mask[rcu]:
+                self._hbat_pointing_direction[rcu] = pointing_direction[rcu]
+                self._hbat_pointing_timestamp[rcu] = timestamp.timestamp()
 
-    @DebugIt()
-    @command(dtype_in=(numpy.double,), dtype_out=int)
-    @only_in_states([DevState.STANDBY, DevState.ON])
-    def set_direction_epochs(self, new_points: numpy.array):
-        if new_points.size != 96:
-            return -1
-
-        self._hbat_pointing_epoch = new_points
-
-        return 0
+    # --------
+    # Commands
+    # --------
 
     @command(dtype_out=str, doc_out="Name of newly installed measures directory")
     @DebugIt()
@@ -124,6 +166,32 @@ class Beam(lofar_device):
         # the new tables
         logger.warning("Restarting device to activate new measures tables")
         restart_python()
+    
+    @command(dtype_in=DevVarStringArray, dtype_out=DevVarDoubleArray)
+    @DebugIt()
+    @log_exceptions()
+    @only_in_states([DevState.ON])
+    def HBAT_delays(self, pointing_direction: numpy.array, timestamp: datetime.datetime = datetime.datetime.now()):
+        """
+        Calculate the delays (in seconds) based on the pointing list and the timestamp
+        TBD: antenna and reference positions will be retrieved from RECV and not stored as BEAM device properties
+        """
+        pointing_direction = numpy.array(pointing_direction).reshape(96,3)
+
+        delays = self._HBAT_delays(pointing_direction, timestamp)
+
+        return delays.flatten()
+    
+    @command(dtype_in=DevVarStringArray)
+    @DebugIt()
+    @only_in_states([DevState.ON])
+    def HBAT_set_pointing(self, pointing_direction: list, timestamp: datetime.datetime = datetime.datetime.now()):
+        """
+        Uploads beam weights based on a given pointing direction 2D array (96 tiles x 3 parameters)
+        """
+        pointing_direction = numpy.array(pointing_direction).reshape(96,3)
+
+        self._HBAT_set_pointing(pointing_direction, timestamp)
 
 # ----------
 # Run server
diff --git a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
index 690f65104b1ada278b7c09447df47de1817941ce..6fed370c4e714813b1a7ce6768cc93209cff1c5e 100644
--- a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
@@ -11,10 +11,8 @@
 
 """
 
-from abc import abstractmethod
-
 # PyTango imports
-from tango.server import Device, command, attribute
+from tango.server import attribute, command, Device, DeviceMeta
 from tango import AttrWriteType, DevState, DebugIt, Attribute, DeviceProxy
 import time
 import math
@@ -23,7 +21,6 @@ import math
 from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.common.lofar_logging import log_exceptions
 from tangostationcontrol.common.lofar_version import get_version
-from tangostationcontrol.devices.abstract_device import AbstractDeviceMetas
 from tangostationcontrol.devices.device_decorators import only_in_states, fault_on_error
 
 
@@ -32,7 +29,8 @@ __all__ = ["lofar_device"]
 import logging
 logger = logging.getLogger()
 
-class lofar_device(Device, metaclass=AbstractDeviceMetas):
+
+class lofar_device(Device, metaclass=DeviceMeta):
     """
 
     **Properties:**
@@ -217,14 +215,12 @@ class lofar_device(Device, metaclass=AbstractDeviceMetas):
     def configure_for_fault(self):
         pass
 
-    @abstractmethod
     def configure_for_off(self):
         pass
 
     def configure_for_on(self):
         pass
 
-    @abstractmethod
     def configure_for_initialise(self):
         pass
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/opcua_device.py b/tangostationcontrol/tangostationcontrol/devices/opcua_device.py
index 6da1fdf21d635e4f32cf848cb4c8c81287b896d6..eb2e508c35cf6923fb9d121f729465a4eca621e3 100644
--- a/tangostationcontrol/tangostationcontrol/devices/opcua_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/opcua_device.py
@@ -17,14 +17,15 @@ import numpy
 import asyncio
 # Additional import
 
-from tangostationcontrol.common.lofar_logging import  log_exceptions
+from tangostationcontrol.common.lofar_logging import log_exceptions
 from tangostationcontrol.clients.opcua_client import OPCUAConnection
 from tangostationcontrol.devices.lofar_device import lofar_device
 
 import logging
 logger = logging.getLogger()
 
-__all__ = ["opcua_device", "main"]
+__all__ = ["opcua_device"]
+
 
 class opcua_device(lofar_device):
     """
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py
index ae8b663dc61b4eafa17a73acaa4efc548c3d4d95..21286acd44b5a83a8ac3fb904f55b2024bbf03fe 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py
@@ -11,8 +11,6 @@
 
 """
 
-from abc import abstractmethod
-
 # PyTango imports
 from tango.server import device_property
 
@@ -32,15 +30,13 @@ import numpy
 
 __all__ = ["Statistics"]
 
-# TODO(Corne): Make Statistics use ABCMeta again when L2SS-551 is fixed
-#              https://support.astron.nl/jira/browse/L2SS-551
+
 class Statistics(opcua_device):
 
     # In derived classes, set this to a subclass of StatisticsCollector
     @property
-    @abstractmethod
     def STATISTICS_COLLECTOR_CLASS(self):
-        pass
+        raise NotImplementedError
 
     # -----------------
     # Device Properties
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
index adef57e3144e297b273ff5b33e77c9fde513ee82..c0b6f7a98894b7c7d660828231935b63c5b0f5da 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
@@ -28,6 +28,7 @@ import numpy
 
 __all__ = ["XST", "main"]
 
+
 class XST(Statistics):
 
     STATISTICS_COLLECTOR_CLASS = XSTCollector
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_beam.py b/tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_beam.py
index b6be958cfde3b9f236947e9b1b76195c844bad40..8e1f2091f41504358619d793aa98ba52761f5e03 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_beam.py
+++ b/tangostationcontrol/tangostationcontrol/integration_test/devices/test_device_beam.py
@@ -7,9 +7,36 @@
 # Distributed under the terms of the APACHE license.
 # See LICENSE.txt for more info.
 
+import numpy
+from tangostationcontrol.integration_test.device_proxy import TestDeviceProxy
+
 from .base import AbstractTestBases
 
 class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
 
     def setUp(self):
         super().setUp("STAT/Beam/1")
+    
+    def test_write_HBAT_delays(self):
+        """ Test whether the delay values are correctly saved into the relative RECV attribute"""
+
+        self.proxy.initialise()
+        self.proxy.on()
+
+        # setup RECV as well
+        recv_proxy = TestDeviceProxy("STAT/RECV/1")
+        recv_proxy.off()
+        recv_proxy.initialise()
+        recv_proxy.on()
+
+        # Verify attribute is present (all zeros if never used before)
+        HBAT_delays_r1 = numpy.array(recv_proxy.read_attribute('HBAT_BF_delays_RW').value)
+        self.assertIsNotNone(HBAT_delays_r1)
+        
+        # Verify writing operation does not lead to errors
+        self.proxy.HBAT_set_pointing(numpy.array([["J2000","0deg","0deg"]] * 96).flatten())  # write values to RECV
+        HBAT_delays_r2 = numpy.array(recv_proxy.read_attribute('HBAT_BF_delays_RW').value)
+        self.assertIsNotNone(HBAT_delays_r2)
+        
+        # Verify delays changed (to be discussed)
+        #self.assertFalse((HBAT_delays_r1==HBAT_delays_r2).all())
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/test_abstract_device.py b/tangostationcontrol/tangostationcontrol/test/devices/test_abstract_device.py
deleted file mode 100644
index 742fa9e405d112444239ae30284e51b8452416e8..0000000000000000000000000000000000000000
--- a/tangostationcontrol/tangostationcontrol/test/devices/test_abstract_device.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# This file is part of the LOFAR 2.0 Station Software
-#
-#
-#
-# Distributed under the terms of the APACHE license.
-# See LICENSE.txt for more info.
-
-import abc
-from unittest import mock
-
-from tango import server
-from tango.server import attribute
-
-from tangostationcontrol.devices.abstract_device import AbstractDeviceMetas
-
-from tangostationcontrol.test import base
-
-
-class TestAbstractDevice(base.TestCase):
-
-    class AbstractExample(object, metaclass=abc.ABCMeta):
-        """A pure abc.ABCMeta metaclass with an abstract method
-
-        This is an abstract class that inherits object with the abc.ABCMeta as
-        metaclass
-        """
-
-        @abc.abstractmethod
-        def example_method(self):
-            raise NotImplementedError
-
-    class TestHardwareDevice(server.Device, metaclass=AbstractDeviceMetas):
-        """This is your overarching abstract class with a combined metaclass
-
-        Device is an object with DeviceMeta as metaclass
-        We use HardwareDeviceMetas as metaclass
-
-        Our metaclass contract is now fulfilled.
-        """
-
-        @attribute(dtype=float)
-        def call_example_method(self):
-            return self.example_method()
-
-        @abc.abstractmethod
-        def example_method(self):
-            raise NotImplementedError
-
-    class ConcreteHardwareDevice(TestHardwareDevice):
-
-        def example_method(self):
-            return 12
-
-    def setUp(self):
-        super(TestAbstractDevice, self).setUp()
-
-    # def test_instance_tango(self):
-    #
-    #     try:
-    #         with DeviceTestContext(self.TestHardwareDevice, process=True) as proxy:
-    #             # Calling this method raises the NotImplementedError exception
-    #             proxy.call_example_method()
-    #     except Exception as e:
-    #         self.assertIsInstance(e, RuntimeError)
-    #
-    #     with DeviceTestContext(self.ConcreteHardwareDevice, process=True) as proxy:
-    #         self.assertEqual(12, proxy.call_example_method)
-
-    @mock.patch.object(server, 'get_worker')
-    @mock.patch.object(server, 'LatestDeviceImpl')
-    def test_instance_error(self, m_worker, m_implement):
-        # Creating this object should raise a type error but it does not
-        # combining metaclasses in this way does not have the desired result.
-        # This is a known limitation of this approach
-        m_device = self.TestHardwareDevice(mock.Mock(), mock.Mock())
-
-        # Raising the NotImplementedError works as expected, however.
-        self.assertRaises(NotImplementedError, m_device.example_method)
-
-        # Creating this object of a class that has a pure metaclass does raise
-        # the expected error.
-        self.assertRaises(TypeError, self.AbstractExample)
-
-    @mock.patch.object(server, 'get_worker')
-    @mock.patch.object(server, 'LatestDeviceImpl')
-    def test_isinstance(self, m_worker, m_implement):
-        m_device = self.TestHardwareDevice(mock.Mock(), mock.Mock())
-
-        self.assertFalse(isinstance(m_device, AbstractDeviceMetas))
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/test_beam_device.py b/tangostationcontrol/tangostationcontrol/test/devices/test_beam_device.py
index 107f95293f587e632f018be68a5cf07764bc49b7..06a6d858114b30a1dc1f1f6ba7314aadf1a2c5c3 100644
--- a/tangostationcontrol/tangostationcontrol/test/devices/test_beam_device.py
+++ b/tangostationcontrol/tangostationcontrol/test/devices/test_beam_device.py
@@ -7,13 +7,12 @@
 # Distributed under the terms of the APACHE license.
 # See LICENSE.txt for more info.
 
-import numpy
-
 from tango import DevState
 from tango.test_context import DeviceTestContext
 
-from tangostationcontrol.devices import beam
+from tangostationcontrol.devices import beam, lofar_device
 
+import numpy
 import mock
 
 from tangostationcontrol.test import base
@@ -24,96 +23,52 @@ class TestBeamDevice(base.TestCase):
     def setUp(self):
         super(TestBeamDevice, self).setUp()
 
-        # lofar_device init_device will launch a DeviceProxy not captured by
-        # the TestDeviceContext making it fail.
-
-        # Patch init_device and force match spec
-        init_patcher = mock.patch.object(
-            beam.Beam, 'init_device', spec=beam.Beam.init_device)
-        self.m_init = init_patcher.start()
-        self.addCleanup(init_patcher.stop)
-
+        # Patch DeviceProxy to allow making the proxies during initialisation
+        # that we otherwise avoid using
+        for device in [beam, lofar_device]:
+            proxy_patcher = mock.patch.object(
+                device, 'DeviceProxy')
+            proxy_patcher.start()
+            self.addCleanup(proxy_patcher.stop)
+    
     def test_get_pointing_directions(self):
         """Verify can read pointings attribute and length matches without err"""
         with DeviceTestContext(beam.Beam, process=True) as proxy:
             self.assertEqual(96, len(proxy.read_attribute(
                 "HBAT_pointing_direction_R").value))
 
-    def test_get_pointing_epochs(self):
-        """Verify can read epochs attribute and length matches without err"""
+    def test_get_pointing_timestamps(self):
+        """Verify can read timestamps attribute and length matches without err"""
 
         with DeviceTestContext(beam.Beam, process=True) as proxy:
             self.assertEqual(96, len(proxy.read_attribute(
-                "HBAT_pointing_epoch_R").value))
-
-    def test_set_pointing_direction(self):
-        """Verify can set pointings attribute without error"""
-
-        with DeviceTestContext(beam.Beam, process=True) as proxy:
-            proxy.init()
-            proxy.Initialise()
-            self.assertEqual(DevState.STANDBY, proxy.state())
-            self.assertEqual(0, proxy.set_direction_pointings(numpy.zeros(96)))
-
-    def test_set_pointing_epochs(self):
-        """Verify can set epochs attribute without error"""
+                "HBAT_pointing_timestamp_R").value))
 
+    def test_HBAT_delays_dims(self):
+        """Verify HBAT delays are retrieved with correct dimensions"""
         with DeviceTestContext(beam.Beam, process=True) as proxy:
             proxy.init()
             proxy.Initialise()
             self.assertEqual(DevState.STANDBY, proxy.state())
-            self.assertEqual(0, proxy.set_direction_epochs(numpy.zeros(96)))
-
-    def pointing(self, attribute: str, lambd):
-        data = numpy.arange(0, 96)
-
+            proxy.set_defaults()
+            proxy.on()
+            self.assertEqual(DevState.ON, proxy.state())
+
+            # verify HBAT_delays method returns the correct dimensions
+            HBAT_delays = proxy.HBAT_delays(numpy.array([["J2000","0deg","0deg"]] * 96).flatten())
+            self.assertEqual((96*16,), HBAT_delays.shape)
+    
+    def test_HBAT_delays_calculations(self):
+        """Verify the calculations from delays to weights"""
         with DeviceTestContext(beam.Beam, process=True) as proxy:
             proxy.init()
             proxy.Initialise()
             self.assertEqual(DevState.STANDBY, proxy.state())
-
-            # Evaluate default all zeros are present using numpy array compare
-            compare_obj = numpy.zeros(96) == proxy.read_attribute(
-                attribute).value
-            self.assertTrue(compare_obj.all())
-
-            # Set direction pointings to range of incrementing values
-            self.assertEqual(0, lambd(proxy, data))
-
-            # Verify attribute has been updated with correct data
-            compare_obj = data == proxy.read_attribute(attribute).value
-            self.assertTrue(compare_obj.all())
-
-    def test_direction_pointing(self):
-        """Set and Get test with actual values for pointing attribute"""
-
-        self.pointing("HBAT_pointing_direction_R", lambda x, y:
-                      x.set_direction_pointings(y))
-
-    def test_direction_epochs(self):
-        """Set and Get test with actual values for pointing attribute"""
-
-        self.pointing("HBAT_pointing_epoch_R", lambda x, y:
-                      x.set_direction_epochs(y))
-
-    def test_pointing_invalid(self):
-        """Test that set pointings command refuses invalid lengths"""
-
-        with DeviceTestContext(beam.Beam, process=True) as proxy:
-            proxy.init()
-            proxy.Initialise()
-            self.assertEqual(DevState.STANDBY, proxy.state())
-
-            # should return error due to invalid length
-            self.assertEqual(-1, proxy.set_direction_pointings(numpy.zeros(55)))
-
-    def test_epoch_invalid(self):
-        """Test that set epochs command refuses invalid lengths"""
-
-        with DeviceTestContext(beam.Beam, process=True) as proxy:
-            proxy.init()
-            proxy.Initialise()
-            self.assertEqual(DevState.STANDBY, proxy.state())
-
-            # should return error due to invalid length
-            self.assertEqual(-1, proxy.set_direction_epochs(numpy.zeros(55)))
+            proxy.set_defaults()
+            proxy.on()
+            self.assertEqual(DevState.ON, proxy.state())
+        
+            # verify if values are actually transformed
+            HBAT_delays = proxy.HBAT_delays(numpy.array([["J2000","0deg","0deg"]] * 96).flatten())
+            HBAT_bf_delays = beam.Beam._calculate_HBAT_bf_delays(HBAT_delays)
+            self.assertNotEqual(HBAT_delays, HBAT_bf_delays)
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/test_statistics_device.py b/tangostationcontrol/tangostationcontrol/test/devices/test_statistics_device.py
new file mode 100644
index 0000000000000000000000000000000000000000..29c2462fe95047bc6364acd0d4c6a03c945801f2
--- /dev/null
+++ b/tangostationcontrol/tangostationcontrol/test/devices/test_statistics_device.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of the LOFAR 2.0 Station Software
+#
+#
+#
+# Distributed under the terms of the APACHE license.
+# See LICENSE.txt for more info.
+
+import mock
+
+from tango import server
+from tango.test_context import DeviceTestContext
+
+from tangostationcontrol.test import base
+
+
+class TestStatisticsDevice(base.TestCase):
+
+    def setUp(self):
+        super(TestStatisticsDevice, self).setUp()
+
+    def test_python_bug(self):
+        """Python is bugged and super() calls in ctypes fail
+
+        This is the same type of issues that prevents combining metaclasses
+        DeviceMeta and ABCMeta
+
+        https://github.com/waveform80/picamera/issues/355
+        https://bugs.python.org/issue29270
+        """
+        import ctypes as ct
+
+        try:
+            class TestSubclass(ct.c_uint32):
+                def __repr__(self):
+                    return super().__repr__()
+        except Exception as e:
+            self.assertIsInstance(e, TypeError)
+
+    @mock.patch.object(server, 'get_worker')
+    def test_instance_statistics(self, m_worker):
+        """Test that we can import and create a statistics device
+
+        The import of Statistics fails when both ABCMeta and DeviceMeta are
+        combined. Leave this test to prevent regressions when reattempting our
+        combined metaclass.
+        """
+
+        from tangostationcontrol.devices.sdp.statistics import Statistics
+
+        with DeviceTestContext(Statistics, process=True) as proxy:
+            self.assertTrue(proxy.ping() > 0)
diff --git a/tangostationcontrol/tox.ini b/tangostationcontrol/tox.ini
index fc0876dd08ba604c5d112e541ef14f5ea04c96c4..fc688b430a9cdaa3805f5340e22826003e553080 100644
--- a/tangostationcontrol/tox.ini
+++ b/tangostationcontrol/tox.ini
@@ -7,6 +7,7 @@ skipsdist = True
 usedevelop = True
 sitepackages = True
 install_command = pip3 install {opts} {packages}
+passenv = HOME
 setenv =
    VIRTUAL_ENV={envdir}
    PYTHONWARNINGS=default::DeprecationWarning