diff --git a/tangostationcontrol/tangostationcontrol/devices/beam.py b/tangostationcontrol/tangostationcontrol/devices/beam.py
index 9540560a9537eca57d16e208defd44dffa8d9814..69f792101b10b7a83374451928315f0d25f379f3 100644
--- a/tangostationcontrol/tangostationcontrol/devices/beam.py
+++ b/tangostationcontrol/tangostationcontrol/devices/beam.py
@@ -67,6 +67,14 @@ class Beam(lofar_device):
         dtype=(numpy.double,), max_dim_x=96,
         fget=lambda self: self._hbat_pointing_timestamp_r)
 
+    HBAT_tracking_enabled_R = attribute(access=AttrWriteType.READ,
+        dtype=numpy.bool,
+        fget=lambda self: self.HBAT_beam_tracker.is_alive())
+
+    HBAT_tracking_enabled_RW = attribute(access=AttrWriteType.READ_WRITE,
+        dtype=numpy.bool,
+        fget=lambda self: self._hbat_tracking_enabled_rw)
+
     # 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.
     measures_directory_R = attribute(dtype=str, access=AttrWriteType.READ, fget = lambda self: get_measures_directory())
@@ -86,6 +94,9 @@ class Beam(lofar_device):
         self._hbat_pointing_direction_r     = numpy.zeros((96,3), dtype="<U32")
         self._hbat_pointing_direction_rw    = numpy.array([["AZELGEO","0deg","90deg"]] * 96, dtype="<U32")
 
+        # Initialise tracking control
+        self._hbat_tracking_enabled_rw      = True
+
         # Set a reference of RECV device
         self.recv_proxy = DeviceProxy("STAT/RECV/1")
 
@@ -107,15 +118,15 @@ class Beam(lofar_device):
         super().configure_for_on()
 
         # Start beam tracking thread
-        self.HBAT_beam_tracker.start()
+        if self._hbat_tracking_enabled_rw:
+            self.HBAT_beam_tracker.start()
     
     @log_exceptions
     def configure_for_off(self):
-        super().configure_for_off()
-
         # Stop thread object
         self.HBAT_beam_tracker.stop()
-        self.HBAT_beam_tracker = None
+
+        super().configure_for_off()
 
     # --------
     # internal functions
@@ -132,6 +143,15 @@ class Beam(lofar_device):
 
         # force update across tiles if pointing changes
         self.HBAT_beam_tracker.force_update()
+        logger.info("Pointing direction update requested")
+
+    def write_HBAT_tracking_enabled_RW(self, value):
+        self._hbat_tracking_enabled_rw = value
+
+        if value:
+            self.HBAT_beam_tracker.start()
+        else:
+            self.HBAT_beam_tracker.stop()
 
     def _HBAT_delays(self, pointing_direction: numpy.array, timestamp: datetime.datetime = datetime.datetime.now()):
         """
@@ -225,6 +245,7 @@ class Beam(lofar_device):
     
     @command(dtype_in=DevVarStringArray)
     @DebugIt()
+    @log_exceptions()
     @only_in_states([DevState.ON])
     def HBAT_set_pointing(self, pointing_direction: list, timestamp: datetime.datetime = datetime.datetime.now()):
         """
@@ -275,7 +296,7 @@ class BeamTracker():
 
     """ Object that encapsulates a Thread, resposible for beam tracking operations """
     def __init__(self, device: lofar_device):
-        self.thread = Thread(target=self._update_HBAT_pointing_direction)
+        self.thread = None
         self.device = device
 
         # Condition to trigger a forced update or early abort
@@ -284,12 +305,17 @@ class BeamTracker():
     
     def start(self):
         """ Starts the Beam Tracking thread """
+        if self.thread:
+            # already started
+            return
+
         self.done = False
+        self.thread = Thread(target=self._update_HBAT_pointing_direction, name=f"BeamTracker of {self.device.get_name()}")
         self.thread.start()
     
     def is_alive(self):
         """ Returns True just before the Thread run() method starts until just after the Thread run() method terminates. """
-        return self.thread.is_alive()
+        return self.thread and self.thread.is_alive()
 
     def force_update(self):
         """ Force the pointing to be updated. """
@@ -301,6 +327,9 @@ class BeamTracker():
     def stop(self):
         """ Stops the Beam Tracking loop """
 
+        if not self.thread:
+            return
+
         self.done = True
         self.force_update()
 
@@ -309,6 +338,8 @@ class BeamTracker():
 
         if self.is_alive():
             logger.error("BeamTracking Thread did not properly terminate")
+
+        self.thread = None
     
     def _get_sleep_time(self):
         """ Computes the sleep time (in seconds) that needs to be waited for the next beam tracking update """  
@@ -324,13 +355,15 @@ class BeamTracker():
             return sleep_time + self.device.HBAT_beam_tracking_interval
         else:
             return sleep_time
-    
+   
+    @log_exceptions()
     def _update_HBAT_pointing_direction(self):
         """ Updates the beam weights using a fixed interval of time """
 
         # Check if  flag beamtracking is true
         with self.update_lock:
             while not self.done:
+                # TODO: Occasionally this still gets called when the beam device is in OFF?
                 self.device.HBAT_set_pointing(numpy.array(self.device.proxy.HBAT_pointing_direction_RW).flatten())
 
                 # sleep until the next update, or when interrupted (this releases the lock, allowing for notification)
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_beam.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_beam.py
index 21c93eab4f434350fa091523a421837513aadf9c..9af017c12df46b3719c367f94a5452cdddebdbed 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_beam.py
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_beam.py
@@ -68,6 +68,7 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
         self.proxy.Initialise()
         self.assertEqual(DevState.STANDBY, self.proxy.state())
         self.proxy.set_defaults()
+        self.proxy.HBAT_tracking_enabled_RW = False
         self.proxy.on()
         self.assertEqual(DevState.ON, self.proxy.state())
 
@@ -90,6 +91,7 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
         recv_proxy = self.setup_recv_proxy()
 
         self.proxy.initialise()
+        self.proxy.HBAT_tracking_enabled_RW = False
         self.proxy.on()
 
         # Point to Zenith
@@ -101,11 +103,40 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
 
         numpy.testing.assert_equal(calculated_HBAT_delay_steps, expected_HBAT_delay_steps)
 
+    def test_pointing_across_horizon(self):
+        # setup RECV as well
+        recv_proxy = self.setup_recv_proxy()
+
+        self.proxy.initialise()
+        self.proxy.HBAT_tracking_enabled_RW = False
+        self.proxy.on()
+
+        # point at north on the horizon
+        self.proxy.HBAT_set_pointing(["AZELGEO","0deg","0deg"] * 96)
+
+        # obtain delays of the X polarisation of all the elements of the first tile
+        north_beam_delay_steps = recv_proxy.HBAT_BF_delay_steps_RW[0].reshape(2,4,4)[0]
+
+        # delays must differ under rotation, or our test will give a false positive
+        self.assertNotEqual(north_beam_delay_steps.tolist(), numpy.rot90(north_beam_delay_steps).tolist())
+
+        for angle in (90,180,270):
+            # point at angle degrees (90=E, 180=S, 270=W)
+            self.proxy.HBAT_set_pointing(["AZELGEO",f"{angle}deg","0deg"] * 96)
+
+            # obtain delays of the X polarisation of all the elements of the first tile
+            angled_beam_delay_steps = recv_proxy.HBAT_BF_delay_steps_RW[0].reshape(2,4,4)[0]
+
+            expected_delay_steps = numpy.rot90(north_beam_delay_steps, k=-(angle/90))
+
+            self.assertListEqual(expected_delay_steps.tolist(), angled_beam_delay_steps.tolist(), msg=f"angle={angle}")
+
     def test_delays_same_as_LOFAR_ref_pointing(self):
         # setup RECV as well
         recv_proxy = self.setup_recv_proxy()
 
         self.proxy.initialise()
+        self.proxy.HBAT_tracking_enabled_RW = False
         self.proxy.on()
 
         # Point to LOFAR 1 ref pointing (0.929342, 0.952579, J2000)
@@ -131,3 +162,24 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
         expected_HBAT_delay_steps = numpy.array([24, 25, 27, 29, 17, 18, 20, 21, 10, 11, 13, 14, 3, 4, 5, 7] * 2, dtype=numpy.int64)
         numpy.testing.assert_equal(calculated_HBAT_delay_steps[0], expected_HBAT_delay_steps)
         numpy.testing.assert_equal(calculated_HBAT_delay_steps[48], expected_HBAT_delay_steps)
+
+    def test_beam_tracking(self):
+        # setup RECV as well
+        recv_proxy = self.setup_recv_proxy()
+
+        self.proxy.initialise()
+        self.proxy.on()
+
+        # check if we're really tracking
+        self.assertTrue(self.proxy.HBAT_tracking_enabled_R)
+
+        # point somewhere
+        new_pointings = [("J2000",f"{tile}deg","0deg") for tile in range(96)]
+        self.proxy.HBAT_pointing_direction_RW = new_pointings
+
+        # wait for tracking thread to pick up and set. should be almost instant
+        time.sleep(0.5)
+
+        # check pointing
+        self.assertListEqual(new_pointings, list(self.proxy.HBAT_pointing_direction_R))
+