diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index eef96688ba969a95709f27c6b0d96e226662d1e3..c642888588327b2369367a21720aa65f123704fc 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -447,6 +447,10 @@ integration_test_docker:
     - name: docker:dind
   variables:
     DOCKER_TLS_CERTDIR: "/certs"
+  artifacts:
+    when: always
+    paths:
+      - log/
   before_script:
     - |
       if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" && -z "$CI_COMMIT_TAG" ]]; then
@@ -465,20 +469,23 @@ integration_test_docker:
     - export BASH_SOURCE=$(pwd)/bootstrap/etc/lofar20rc.sh
 #    Hack HOSTNAME env variable into host.docker.internal, set in docker-compose
     - export HOSTNAME=host.docker.internal
-#    - export HOSTNAME=$(hostname -i)
-#    - export HOSTNAME=$(cat /run/systemd/netif/leases/2 | grep ^ADDRESS= | awk -F'=' '{print $2}')
 #    source the lofarrc file and mask its non zero exit code
     - . bootstrap/etc/lofar20rc.sh || true
 #    TANGO_HOST must be unset our databaseds will be unreachable
     - unset TANGO_HOST
-##    Allow docker image script to execute
-#    - chmod u+x $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh
 #    Do not remove 'bash' or statement will be ignored by primitive docker shell
     - bash $CI_PROJECT_DIR/sbin/tag_and_push_docker_image.sh pull $tag
-##    Allow integration test to execute
-#    - chmod u+x $CI_PROJECT_DIR/sbin/run_integration_test.sh
 #    Do not remove 'bash' or statement will be ignored by primitive docker shell
     - bash $CI_PROJECT_DIR/sbin/run_integration_test.sh
+  after_script:
+#    Collect output of all containers
+    - |
+      mkdir -p log
+      for container in $(docker ps -a --format "{{.Names}}")
+      do
+        echo "Saving log for container $container"
+        docker logs "${container}" >& "log/${container}.log"
+      done
 wheel_packaging:
   stage: packaging
   artifacts:
diff --git a/docker-compose/Makefile b/docker-compose/Makefile
index 5aa715b84f64f4038ce946aa2cd9c33f9c53ba23..1f859907bd6eb9038c569e24fd2a40a339145ca5 100644
--- a/docker-compose/Makefile
+++ b/docker-compose/Makefile
@@ -181,6 +181,7 @@ bootstrap: pull build # first start, initialise from scratch
 	$(MAKE) start dsconfig # boot up containers to load configurations
 	sleep 5 # wait for dsconfig container to come up
 	../sbin/update_ConfigDb.sh ../CDB/LOFAR_ConfigDb.json # load default configuration
+	../sbin/update_ConfigDb.sh ../CDB/tango-archiver-data/archiver-devices.json # load default archive configuration
 	../sbin/update_ConfigDb.sh ../CDB/stations/simulators_ConfigDb.json # by default, use simulators
 
 start: up ## start a service (usage: make start <servicename>)
diff --git a/docker-compose/tango.yml b/docker-compose/tango.yml
index 166891b51f9a1ac59d3fcf837c3486f3199ad798..5a6839f44a356113ae1fc525a0ff6e3290e777cd 100644
--- a/docker-compose/tango.yml
+++ b/docker-compose/tango.yml
@@ -80,12 +80,10 @@ services:
       - TANGO_HOST=${TANGO_HOST}
     command: >
       sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict --
-             json2tango -w -a -u /tango-archiver-data/archiver-devices.json &&
              sleep infinity"
     volumes:
       - ..:/opt/lofar/tango:rw
       - ${HOME}:/hosthome
-      - ../CDB/tango-archiver-data:/tango-archiver-data
     logging:
       driver: syslog
       options:
diff --git a/sbin/run_integration_test.sh b/sbin/run_integration_test.sh
index 343eac0520e9e4ece9a4e7144e8ebd1b1e165753..acac6e21e1aeb0850d19aa420a4fe5c9a72970b9 100755
--- a/sbin/run_integration_test.sh
+++ b/sbin/run_integration_test.sh
@@ -20,31 +20,39 @@ sleep 1 # dsconfig container must be up and running...
 # shellcheck disable=SC2016
 echo '/usr/local/bin/wait-for-it.sh ${TANGO_HOST} --strict --timeout=300 -- true' | make run dsconfig bash -
 
+DEVICES="device-boot device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam"
+SIMULATORS="sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim"
+
 # Build only the required images, please do not build everything that makes CI
 # take really long to finish, especially grafana / jupyter / prometheus.
 # jupyter is physically large > 2.5gb and overlayfs is really slow.
-make build device-sdp device-recv device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam 
-make build sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim
+# shellcheck disable=SC2086
+make build $DEVICES $SIMULATORS
 make build elk integration-test
 make build archiver-timescale hdbppts-cm hdbppts-es
 
 # Start and stop sequence
-make stop device-boot device-docker device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-beamlet device-digitalbeam device-tilebeam sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim hdbppts-es hdbppts-cm archiver-timescale
+# shellcheck disable=SC2086
+make stop $DEVICES $SIMULATORS hdbppts-es hdbppts-cm archiver-timescale
+make stop device-docker # this one does not test well in docker-in-docker
 make start elk
 
 # Update the dsconfig
 # Do not remove `bash`, otherwise statement ignored by gitlab ci shell!
 bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/LOFAR_ConfigDb.json
+bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/tango-archiver-data/archiver-devices.json
 bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/stations/simulators_ConfigDb.json
 bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/stations/dummy_positions_ConfigDb.json
 
 cd "$LOFAR20_DIR/docker-compose" || exit 1
-make start sdptr-sim recv-sim unb2-sim apsct-sim apspu-sim
+# shellcheck disable=SC2086
+make start $SIMULATORS
 
 # Give the simulators time to start
 sleep 5
 
-make start device-boot device-apsct device-apspu device-sdp device-recv device-sst device-unb2 device-xst device-tilebeam device-beamlet device-digitalbeam
+# shellcheck disable=SC2086
+make start $DEVICES
 # Archive devices -> starting order is important
 make start archiver-timescale hdbppts-cm hdbppts-es
 
@@ -63,4 +71,5 @@ make run integration-test default
 bash "${LOFAR20_DIR}"/sbin/update_ConfigDb.sh "${LOFAR20_DIR}"/CDB/integrations/recvcluster_ConfigDb.json
 make restart device-recv device-tilebeam
 sleep 5
+
 make run integration-test recv_cluster
diff --git a/tangostationcontrol/tangostationcontrol/devices/apsct.py b/tangostationcontrol/tangostationcontrol/devices/apsct.py
index dd8bd1c2a7698d2c2481dbb52d60e99541f7e43b..75ef8f612b3bfd44735444fba95d8927226fe55a 100644
--- a/tangostationcontrol/tangostationcontrol/devices/apsct.py
+++ b/tangostationcontrol/tangostationcontrol/devices/apsct.py
@@ -14,7 +14,7 @@
 # PyTango imports
 from tango import DebugIt
 from tango.server import command, attribute, device_property
-from tango import AttrWriteType, DevState
+from tango import AttrWriteType
 import numpy
 # Additional import
 
@@ -23,6 +23,7 @@ from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
 from tangostationcontrol.devices.device_decorators import *
 from tangostationcontrol.devices.opcua_device import opcua_device
+from tangostationcontrol.devices.lofar_device import lofar_device
 
 import logging
 logger = logging.getLogger()
@@ -138,7 +139,7 @@ class APSCT(opcua_device):
 
     @command()
     @DebugIt()
-    @only_in_states([DevState.STANDBY, DevState.ON])
+    @only_in_states(lofar_device.DEFAULT_COMMAND_STATES)
     def APSCT_off(self):
         """
 
@@ -148,7 +149,7 @@ class APSCT(opcua_device):
 
     @command()
     @DebugIt()
-    @only_in_states([DevState.STANDBY, DevState.ON])
+    @only_in_states(lofar_device.DEFAULT_COMMAND_STATES)
     def APSCT_200MHz_on(self):
         """
 
@@ -158,7 +159,7 @@ class APSCT(opcua_device):
 
     @command()
     @DebugIt()
-    @only_in_states([DevState.STANDBY, DevState.ON])
+    @only_in_states(lofar_device.DEFAULT_COMMAND_STATES)
     def APSCT_160MHz_on(self):
         """
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/beam_device.py b/tangostationcontrol/tangostationcontrol/devices/beam_device.py
new file mode 100644
index 0000000000000000000000000000000000000000..0b436d89b2191b33f059094a89740d66382d927b
--- /dev/null
+++ b/tangostationcontrol/tangostationcontrol/devices/beam_device.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+#
+# Distributed under the terms of the APACHE license.
+# See LICENSE.txt for more info.
+
+"""Beam Abstract Device Server for LOFAR2.0
+
+"""
+# PyTango imports
+from tango.server import attribute, command
+from tango import AttrWriteType, DebugIt
+
+# Additional import
+from tangostationcontrol.common.entrypoint import entry
+from tangostationcontrol.common.measures import get_measures_directory, get_available_measures_directories, download_measures, use_measures_directory, restart_python
+from tangostationcontrol.common.lofar_logging import log_exceptions
+from tangostationcontrol.devices.lofar_device import lofar_device
+
+__all__ = ["beam_device", "main"]
+
+import logging
+logger = logging.getLogger()
+
+
+class beam_device(lofar_device):
+    
+    # ----------
+    # Attributes
+    # ----------
+
+    # 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())
+
+    # List of dowloaded measures (the latest 64, anyway)
+    measures_directories_available_R = attribute(dtype=(str,), max_dim_x=64, access=AttrWriteType.READ, fget = lambda self: sorted(get_available_measures_directories())[-64:])
+
+    # --------
+    # Commands
+    # --------
+
+    @command(dtype_out=str, doc_out="Name of newly installed measures directory")
+    @DebugIt()
+    @log_exceptions()
+    def download_measures(self):
+        """ Download new measures tables into /opt/IERS, but do not activate them.
+        
+            NOTE: This may take a while to complete. You are advised to increase
+                  the timeout of the proxy using `my_device.set_timeout_millis(10000)`. """
+
+        return download_measures()
+    
+    @command(dtype_in=str, doc_in="Measures directory to activate")
+    @DebugIt()
+    @log_exceptions()
+    def use_measures(self, newdir):
+        """ Activate a downloaded set of measures tables.
+        
+            NOTE: This will turn off and restart this device!! """
+
+        # switch to requested measures
+        use_measures_directory(newdir)
+        logger.info(f"Switched measures table to {newdir}")
+
+        # turn off our device, to prepare for a python restart
+        self.Off()
+
+        # restart this program to force casacore to adopt
+        # the new tables
+        logger.warning("Restarting device to activate new measures tables")
+        restart_python()
+
+# ----------
+# Run server
+# ----------
+def main(**kwargs):
+    """Main function of the Docker module."""
+    return entry(beam_device, **kwargs)
diff --git a/tangostationcontrol/tangostationcontrol/devices/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py
index 59427165c20f5c8f9a65e9f59b0d85c4a3fa8837..47dcc3741e2f5e72aa3bb7fa2c6fb35f551d9fdc 100644
--- a/tangostationcontrol/tangostationcontrol/devices/boot.py
+++ b/tangostationcontrol/tangostationcontrol/devices/boot.py
@@ -153,7 +153,7 @@ class DevicesInitialiser(object):
                 continue
 
             if self.is_available(device):
-                if self.reboot or self.devices[device].state() not in [DevState.ON, DevState.ALARM]:
+                if self.reboot or self.devices[device].state() not in lofar_device.OPERATIONAL_STATES:
                     self.stop_device(device)
                     self.boot_device(device)
 
@@ -204,7 +204,7 @@ class DevicesInitialiser(object):
         else:
             proxy.warm_boot()
 
-        if proxy.state() not in [DevState.ON, DevState.ALARM]: # ALARM still means booting was succesful
+        if proxy.state() not in lofar_device.OPERATIONAL_STATES:
             raise InitialisationException(f"Could not boot device {device_name}. It reports status: {proxy.status()}")
 
         self.set_status(f"[restarting {device_name}] Succesfully booted.")
@@ -313,14 +313,14 @@ class Boot(lofar_device):
 
     @command()
     @DebugIt()
-    @only_in_states([DevState.ON])
+    @only_in_states(lofar_device.OPERATIONAL_STATES)
     @log_exceptions()
     def boot(self):
         self._boot(reboot=False, initialise_hardware=self.Initialise_Hardware)
 
     @command()
     @DebugIt()
-    @only_in_states([DevState.ON])
+    @only_in_states(lofar_device.OPERATIONAL_STATES)
     @log_exceptions()
     def reboot(self):
         self._boot(reboot=True, initialise_hardware=self.Initialise_Hardware)
diff --git a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
index 50368d15d59fd94794edfaafdb2c451513b60b24..cc276428d962fa006d2ef0619790b65c1f2ba270 100644
--- a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
@@ -41,6 +41,7 @@ class lofar_device(Device, metaclass=DeviceMeta):
         INIT    = Device is initialising.
         STANDBY = Device is initialised, but pends external configuration and an explicit turning on,
         ON      = Device is fully configured, functional, controls the hardware, and is possibly actively running,
+        ALARM   = Device is operating but one of its attributes is out of range,
         FAULT   = Device detected an unrecoverable error, and is thus malfunctional,
         OFF     = Device is turned off, drops connection to the hardware,
 
@@ -49,6 +50,7 @@ class lofar_device(Device, metaclass=DeviceMeta):
         OFF  -> INIT:    Triggered by device. Device will initialise (connect to hardware, other devices),
         INIT -> STANDBY: Triggered by device. Device is initialised, and is ready for additional configuration by the user,
         STANDBY -> ON:   Triggered by user.   Device reports to be functional,
+        ON -> ALARM:     Triggered by tango.  Device has attribute(s) with value(s) exceeding their alarm treshold,
         * -> FAULT:      Triggered by device. Device has degraded to malfunctional, for example because the connection to the hardware is lost,
         * -> FAULT:      Triggered by user.   Emulate a forced malfunction for integration testing purposes,
         * -> OFF:        Triggered by user.   Device is turned off. Triggered by the Off() command,
@@ -57,6 +59,17 @@ class lofar_device(Device, metaclass=DeviceMeta):
         The user triggers their transitions by the commands reflecting the target state (Initialise(), On(), Fault()).
     """
 
+    # The Device states in which we consider our device operational,
+    # and thus allow interaction.
+    OPERATIONAL_STATES = [DevState.ON, DevState.ALARM]
+
+    # States in which Initialise() has happened, and the hardware
+    # can thus be configured or otherwise interacted with.
+    INITIALISED_STATES = OPERATIONAL_STATES + [DevState.STANDBY]
+
+    # States in which most commands are allowed
+    DEFAULT_COMMAND_STATES = INITIALISED_STATES
+
     # ----------
     # Attributes
     # ----------
@@ -159,7 +172,7 @@ class lofar_device(Device, metaclass=DeviceMeta):
         self.set_status("Device is in the STANDBY state.")
 
     @command()
-    @only_in_states([DevState.STANDBY, DevState.ON])
+    @only_in_states(INITIALISED_STATES)
     @DebugIt()
     @fault_on_error()
     @log_exceptions()
@@ -204,7 +217,6 @@ class lofar_device(Device, metaclass=DeviceMeta):
 
 
     @command()
-    @only_in_states([DevState.ON, DevState.INIT, DevState.STANDBY, DevState.FAULT])
     @DebugIt()
     @log_exceptions()
     def Fault(self, new_status="Device is in the FAULT state."):
@@ -216,6 +228,9 @@ class lofar_device(Device, metaclass=DeviceMeta):
 
         :return:None
         """
+        if self.get_state() == DevState.OFF:
+            raise Exception("IllegalCommand: Cannot go from FAULT -> OFF")
+
         if self.get_state() == DevState.FAULT:
             # Already faulting. Don't complain.
             logger.warning("Requested to go to FAULT state, but am already in FAULT state.")
@@ -272,7 +287,7 @@ class lofar_device(Device, metaclass=DeviceMeta):
         pass
 
     @command()
-    @only_in_states([DevState.STANDBY, DevState.ON])
+    @only_in_states(DEFAULT_COMMAND_STATES)
     @DebugIt()
     @log_exceptions()
     def set_defaults(self):
@@ -302,7 +317,7 @@ class lofar_device(Device, metaclass=DeviceMeta):
         self._set_defaults(attributes_to_set)
 
 
-    @only_in_states([DevState.STANDBY, DevState.INIT, DevState.ON])
+    @only_in_states(DEFAULT_COMMAND_STATES)
     @fault_on_error()
     @command()
     def set_translator_defaults(self):
@@ -311,7 +326,7 @@ class lofar_device(Device, metaclass=DeviceMeta):
         # This is just the command version of _set_translator_defaults().
         self._set_translator_defaults()
 
-    @only_in_states([DevState.STANDBY, DevState.INIT, DevState.ON])
+    @only_in_states(DEFAULT_COMMAND_STATES)
     @fault_on_error()
     @command()
     @DebugIt()
@@ -321,7 +336,7 @@ class lofar_device(Device, metaclass=DeviceMeta):
         # This is just the command version of _prepare_hardware().
         self._prepare_hardware()
 
-    @only_in_states([DevState.STANDBY, DevState.INIT, DevState.ON])
+    @only_in_states(DEFAULT_COMMAND_STATES)
     @fault_on_error()
     @command()
     @DebugIt()
@@ -331,7 +346,7 @@ class lofar_device(Device, metaclass=DeviceMeta):
         # This is just the command version of _initialise_hardware().
         self._initialise_hardware()
     
-    @only_in_states([DevState.STANDBY, DevState.ON])
+    @only_in_states(DEFAULT_COMMAND_STATES)
     @command(dtype_out = DevDouble)
     def max_archiving_load(self):
         """ Return the maximum archiving load for the device attributes """
diff --git a/tangostationcontrol/tangostationcontrol/devices/recv.py b/tangostationcontrol/tangostationcontrol/devices/recv.py
index 1c21c006221289d2847033f9830fef8760009c3e..ddac029a61102834374baa6d38745d59a0769739 100644
--- a/tangostationcontrol/tangostationcontrol/devices/recv.py
+++ b/tangostationcontrol/tangostationcontrol/devices/recv.py
@@ -16,7 +16,7 @@ from functools import partial
 from tango import DebugIt
 from tango.server import command
 from tango.server import device_property, attribute
-from tango import AttrWriteType, DevState, DevVarFloatArray
+from tango import AttrWriteType, DevVarFloatArray
 
 import numpy
 from math import pi
@@ -29,6 +29,7 @@ from tangostationcontrol.common.lofar_logging import device_logging_to_python
 from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.devices.device_decorators import *
 from tangostationcontrol.devices.opcua_device import opcua_device
+from tangostationcontrol.devices.lofar_device import lofar_device
 
 import logging
 logger = logging.getLogger()
@@ -372,7 +373,7 @@ class RECV(opcua_device):
 
     @command()
     @DebugIt()
-    @only_in_states([DevState.STANDBY, DevState.ON])
+    @only_in_states(lofar_device.DEFAULT_COMMAND_STATES)
     def RCU_off(self):
         """
 
@@ -382,7 +383,7 @@ class RECV(opcua_device):
 
     @command()
     @DebugIt()
-    @only_in_states([DevState.STANDBY, DevState.ON])
+    @only_in_states(lofar_device.DEFAULT_COMMAND_STATES)
     def RCU_on(self):
         """
 
@@ -392,7 +393,7 @@ class RECV(opcua_device):
 
     @command()
     @DebugIt()
-    @only_in_states([DevState.STANDBY, DevState.ON])
+    @only_in_states(lofar_device.DEFAULT_COMMAND_STATES)
     def RCU_DTH_off(self):
         """
 
@@ -402,7 +403,7 @@ class RECV(opcua_device):
 
     @command()
     @DebugIt()
-    @only_in_states([DevState.STANDBY, DevState.ON])
+    @only_in_states(lofar_device.DEFAULT_COMMAND_STATES)
     def RCU_DTH_on(self):
         """
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py b/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py
index 147b0a6237d14b70683f778f220f304ffb2e3b86..256bd5b2cccd8531b2e9ff9aeedcc1acf25cd425 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py
@@ -14,14 +14,14 @@
 
 from tangostationcontrol.common.entrypoint import entry
 #from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
-from tangostationcontrol.devices.lofar_device import lofar_device
+from tangostationcontrol.devices.beam_device import beam_device
 
 #import numpy
 
 __all__ = ["DigitalBeam", "main"]
 
 
-class DigitalBeam(lofar_device):
+class DigitalBeam(beam_device):
     pass
     # -----------------
     # Device Properties
diff --git a/tangostationcontrol/tangostationcontrol/devices/tilebeam.py b/tangostationcontrol/tangostationcontrol/devices/tilebeam.py
index aa83c96f142dae5e8dac24767f50cf89e38c6a7a..7adee9e269bf24d340175d1704448ded674c3684 100644
--- a/tangostationcontrol/tangostationcontrol/devices/tilebeam.py
+++ b/tangostationcontrol/tangostationcontrol/devices/tilebeam.py
@@ -12,17 +12,16 @@ import datetime
 from json import loads
 
 from threading import Thread, Lock, Condition
-from tango import AttrWriteType, DebugIt, DevState, DeviceProxy, DevVarStringArray, DevVarDoubleArray, DevString, DevSource
+from tango import AttrWriteType, DebugIt, DeviceProxy, DevVarStringArray, DevVarDoubleArray, DevString, DevSource
 from tango.server import attribute, command, device_property
 from tango import Util
 
 # Additional import
 from tangostationcontrol.common.entrypoint import entry
-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 *
+from tangostationcontrol.devices.beam_device import beam_device
 
 import logging
 logger = logging.getLogger()
@@ -32,7 +31,7 @@ logger = logging.getLogger()
 __all__ = ["TileBeam", "main", "BeamTracker"]
 
 @device_logging_to_python()
-class TileBeam(lofar_device):
+class TileBeam(beam_device):
 
     # -----------------
     # Device Properties
@@ -78,13 +77,6 @@ class TileBeam(lofar_device):
         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())
-
-    # List of dowloaded measures (the latest 64, anyway)
-    measures_directories_available_R = attribute(dtype=(str,), max_dim_x=64, access=AttrWriteType.READ, fget = lambda self: sorted(get_available_measures_directories())[-64:])
-
     # --------
     # overloaded functions
     # --------
@@ -223,42 +215,11 @@ class TileBeam(lofar_device):
     # --------
     # Commands
     # --------
-
-    @command(dtype_out=str, doc_out="Name of newly installed measures directory")
-    @DebugIt()
-    @log_exceptions()
-    def download_measures(self):
-        """ Download new measures tables into /opt/IERS, but do not activate them.
-        
-            NOTE: This may take a while to complete. You are advised to increase
-                  the timeout of the proxy using `my_device.set_timeout_millis(10000)`. """
-
-        return download_measures()
-
-    @command(dtype_in=str, doc_in="Measures directory to activate")
-    @DebugIt()
-    @log_exceptions()
-    def use_measures(self, newdir):
-        """ Activate a downloaded set of measures tables.
-        
-            NOTE: This will turn off and restart this device!! """
-
-        # switch to requested measures
-        use_measures_directory(newdir)
-        logger.info(f"Switched measures table to {newdir}")
-
-        # turn off our device, to prepare for a python restart
-        self.Off()
-
-        # restart this program to force casacore to adopt
-        # 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, DevState.STANDBY])
+    @only_in_states(beam_device.DEFAULT_COMMAND_STATES)
     def HBAT_delays(self, pointing_direction: numpy.array, timestamp: datetime.datetime = None):
         """
         Calculate the delays (in seconds) based on the pointing list and the timestamp
@@ -279,7 +240,7 @@ class TileBeam(lofar_device):
     @command(dtype_in=DevVarStringArray)
     @DebugIt()
     @log_exceptions()
-    @only_in_states([DevState.ON, DevState.STANDBY])
+    @only_in_states(beam_device.DEFAULT_COMMAND_STATES)
     def HBAT_set_pointing(self, pointing_direction: list, timestamp: datetime.datetime = None):
         """
         Uploads beam weights based on a given pointing direction 2D array (96 tiles x 3 parameters)
@@ -297,7 +258,7 @@ class TileBeam(lofar_device):
 
     @command(dtype_in = DevString)
     @DebugIt()
-    @only_in_states([DevState.ON, DevState.STANDBY])
+    @only_in_states(beam_device.DEFAULT_COMMAND_STATES)
     def HBAT_set_pointing_for_specific_time(self, parameters: DevString = None):
         """
         Uploads beam weights based on a given pointing direction 2D array (96 tiles x 3 parameters)
@@ -334,7 +295,7 @@ class BeamTracker():
     DISCONNECT_TIMEOUT = 3.0
 
     """ Object that encapsulates a Thread, resposible for beam tracking operations """
-    def __init__(self, device: lofar_device):
+    def __init__(self, device: beam_device):
         self.thread = None
         self.device = device
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/unb2.py b/tangostationcontrol/tangostationcontrol/devices/unb2.py
index 614055a716ce8a527197aaad159273ebfda220ef..a255cd7a25358e38ed8d807476b5786596acd773 100644
--- a/tangostationcontrol/tangostationcontrol/devices/unb2.py
+++ b/tangostationcontrol/tangostationcontrol/devices/unb2.py
@@ -13,12 +13,13 @@
 
 # PyTango imports
 from tango.server import command, attribute, device_property
-from tango import AttrWriteType, DebugIt, DevState
+from tango import AttrWriteType, DebugIt
 # 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.devices.lofar_device import lofar_device
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
 from tangostationcontrol.devices.device_decorators import only_in_states
 
@@ -203,7 +204,7 @@ class UNB2(opcua_device):
 
     @command()
     @DebugIt()
-    @only_in_states([DevState.STANDBY, DevState.ON])
+    @only_in_states(lofar_device.DEFAULT_COMMAND_STATES)
     def UNB2_off(self):
         """
 
@@ -213,7 +214,7 @@ class UNB2(opcua_device):
 
     @command()
     @DebugIt()
-    @only_in_states([DevState.STANDBY, DevState.ON])
+    @only_in_states(lofar_device.DEFAULT_COMMAND_STATES)
     def UNB2_on(self):
         """